Skip to content

Possibly ill-formed pattern match involving method name crashes the compiler with NPE #10474

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
maemre opened this issue Aug 19, 2017 · 4 comments
Assignees
Milestone

Comments

@maemre
Copy link

maemre commented Aug 19, 2017

I accidentally created a path-dependent pattern match clause involving a method and it crashed the compiler. I minimized it to the code snippet below. I tried it with Scala 2.12.3 and OpenJDK 1.8.0_131 on Ubuntu 16.04.

object Test {
  def Foo(a: Int): Char = ???

  object Bar

  def crash[A](): Boolean = Bar match {
    case Foo.Bar  true
    case _  false
  }
}

This is the resulting stack trace:

$ scalac parser.scala
error: java.lang.NullPointerException
	at scala.tools.nsc.ast.TreeInfo$ValueClass$.$anonfun$valueUnbox$1(TreeInfo.scala:45)
	at scala.tools.nsc.ast.TreeInfo$ValueClass$.valueUnbox(TreeInfo.scala:45)
	at scala.tools.nsc.ast.TreeInfo$ValueClass$Unbox$.unapply(TreeInfo.scala:50)
	at scala.tools.nsc.ast.TreeInfo$ValueClass$BoxAndUnbox$.unapply(TreeInfo.scala:64)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:37)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.reflect.internal.Trees.itransform(Trees.scala:1379)
	at scala.reflect.internal.Trees.itransform$(Trees.scala:1347)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:44)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:35)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.reflect.internal.Trees.itransform(Trees.scala:1432)
	at scala.reflect.internal.Trees.itransform$(Trees.scala:1347)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:44)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:35)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.reflect.api.Trees$Transformer.$anonfun$transformStats$1(Trees.scala:2589)
	at scala.reflect.api.Trees$Transformer.transformStats(Trees.scala:2587)
	at scala.reflect.internal.Trees.itransform(Trees.scala:1377)
	at scala.reflect.internal.Trees.itransform$(Trees.scala:1347)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:44)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:35)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.reflect.internal.Trees.$anonfun$itransform$2(Trees.scala:1374)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:30)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:25)
	at scala.reflect.internal.Trees.itransform(Trees.scala:1372)
	at scala.reflect.internal.Trees.itransform$(Trees.scala:1347)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:44)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:35)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.reflect.api.Trees$Transformer.$anonfun$transformStats$1(Trees.scala:2589)
	at scala.reflect.api.Trees$Transformer.transformStats(Trees.scala:2587)
	at scala.reflect.internal.Trees.itransform(Trees.scala:1415)
	at scala.reflect.internal.Trees.itransform$(Trees.scala:1347)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.super$transform(TypingTransformers.scala:40)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.$anonfun$transform$1(TypingTransformers.scala:40)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:30)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:25)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:35)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.reflect.api.Trees$Transformer.transformTemplate(Trees.scala:2563)
	at scala.reflect.internal.Trees.$anonfun$itransform$4(Trees.scala:1419)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:30)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:25)
	at scala.reflect.internal.Trees.itransform(Trees.scala:1418)
	at scala.reflect.internal.Trees.itransform$(Trees.scala:1347)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:44)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:35)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.reflect.api.Trees$Transformer.$anonfun$transformStats$1(Trees.scala:2589)
	at scala.reflect.api.Trees$Transformer.transformStats(Trees.scala:2587)
	at scala.reflect.internal.Trees.$anonfun$itransform$7(Trees.scala:1437)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:30)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:25)
	at scala.reflect.internal.Trees.itransform(Trees.scala:1437)
	at scala.reflect.internal.Trees.itransform$(Trees.scala:1347)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.super$transform(TypingTransformers.scala:40)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.$anonfun$transform$2(TypingTransformers.scala:42)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:30)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:25)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:35)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.tools.nsc.ast.Trees$Transformer.transformUnit(Trees.scala:140)
	at scala.tools.nsc.transform.Transform$Phase.apply(Transform.scala:30)
	at scala.tools.nsc.Global$GlobalPhase.$anonfun$applyPhase$1(Global.scala:426)
	at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:419)
	at scala.tools.nsc.Global$GlobalPhase.$anonfun$run$1(Global.scala:390)
	at scala.tools.nsc.Global$GlobalPhase.$anonfun$run$1$adapted(Global.scala:390)
	at scala.collection.Iterator.foreach(Iterator.scala:929)
	at scala.collection.Iterator.foreach$(Iterator.scala:929)
	at scala.collection.AbstractIterator.foreach(Iterator.scala:1417)
	at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:390)
	at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1431)
	at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1416)
	at scala.tools.nsc.Global$Run.compileSources(Global.scala:1412)
	at scala.tools.nsc.Global$Run.compile(Global.scala:1515)
	at scala.tools.nsc.Driver.doCompile(Driver.scala:35)
	at scala.tools.nsc.MainClass.doCompile(Main.scala:24)
	at scala.tools.nsc.Driver.process(Driver.scala:55)
	at scala.tools.nsc.Driver.main(Driver.scala:68)
	at scala.tools.nsc.Main.main(Main.scala)
Exception in thread "main" java.lang.NullPointerException
	at scala.tools.nsc.ast.TreeInfo$ValueClass$.$anonfun$valueUnbox$1(TreeInfo.scala:45)
	at scala.tools.nsc.ast.TreeInfo$ValueClass$.valueUnbox(TreeInfo.scala:45)
	at scala.tools.nsc.ast.TreeInfo$ValueClass$Unbox$.unapply(TreeInfo.scala:50)
	at scala.tools.nsc.ast.TreeInfo$ValueClass$BoxAndUnbox$.unapply(TreeInfo.scala:64)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:37)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.reflect.internal.Trees.itransform(Trees.scala:1379)
	at scala.reflect.internal.Trees.itransform$(Trees.scala:1347)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:44)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:35)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.reflect.internal.Trees.itransform(Trees.scala:1432)
	at scala.reflect.internal.Trees.itransform$(Trees.scala:1347)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:44)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:35)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.reflect.api.Trees$Transformer.$anonfun$transformStats$1(Trees.scala:2589)
	at scala.reflect.api.Trees$Transformer.transformStats(Trees.scala:2587)
	at scala.reflect.internal.Trees.itransform(Trees.scala:1377)
	at scala.reflect.internal.Trees.itransform$(Trees.scala:1347)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:44)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:35)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.reflect.internal.Trees.$anonfun$itransform$2(Trees.scala:1374)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:30)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:25)
	at scala.reflect.internal.Trees.itransform(Trees.scala:1372)
	at scala.reflect.internal.Trees.itransform$(Trees.scala:1347)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:44)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:35)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.reflect.api.Trees$Transformer.$anonfun$transformStats$1(Trees.scala:2589)
	at scala.reflect.api.Trees$Transformer.transformStats(Trees.scala:2587)
	at scala.reflect.internal.Trees.itransform(Trees.scala:1415)
	at scala.reflect.internal.Trees.itransform$(Trees.scala:1347)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.super$transform(TypingTransformers.scala:40)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.$anonfun$transform$1(TypingTransformers.scala:40)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:30)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:25)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:35)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.reflect.api.Trees$Transformer.transformTemplate(Trees.scala:2563)
	at scala.reflect.internal.Trees.$anonfun$itransform$4(Trees.scala:1419)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:30)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:25)
	at scala.reflect.internal.Trees.itransform(Trees.scala:1418)
	at scala.reflect.internal.Trees.itransform$(Trees.scala:1347)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:44)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:35)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.reflect.api.Trees$Transformer.$anonfun$transformStats$1(Trees.scala:2589)
	at scala.reflect.api.Trees$Transformer.transformStats(Trees.scala:2587)
	at scala.reflect.internal.Trees.$anonfun$itransform$7(Trees.scala:1437)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:30)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:25)
	at scala.reflect.internal.Trees.itransform(Trees.scala:1437)
	at scala.reflect.internal.Trees.itransform$(Trees.scala:1347)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
	at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.super$transform(TypingTransformers.scala:40)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.$anonfun$transform$2(TypingTransformers.scala:42)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.atOwner(TypingTransformers.scala:30)
	at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:25)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:35)
	at scala.tools.nsc.transform.PostErasure$PostErasureTransformer.transform(PostErasure.scala:22)
	at scala.tools.nsc.ast.Trees$Transformer.transformUnit(Trees.scala:140)
	at scala.tools.nsc.transform.Transform$Phase.apply(Transform.scala:30)
	at scala.tools.nsc.Global$GlobalPhase.$anonfun$applyPhase$1(Global.scala:426)
	at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:419)
	at scala.tools.nsc.Global$GlobalPhase.$anonfun$run$1(Global.scala:390)
	at scala.tools.nsc.Global$GlobalPhase.$anonfun$run$1$adapted(Global.scala:390)
	at scala.collection.Iterator.foreach(Iterator.scala:929)
	at scala.collection.Iterator.foreach$(Iterator.scala:929)
	at scala.collection.AbstractIterator.foreach(Iterator.scala:1417)
	at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:390)
	at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1431)
	at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1416)
	at scala.tools.nsc.Global$Run.compileSources(Global.scala:1412)
	at scala.tools.nsc.Global$Run.compile(Global.scala:1515)
	at scala.tools.nsc.Driver.doCompile(Driver.scala:35)
	at scala.tools.nsc.MainClass.doCompile(Main.scala:24)
	at scala.tools.nsc.Driver.process(Driver.scala:55)
	at scala.tools.nsc.Driver.main(Driver.scala:68)
	at scala.tools.nsc.Main.main(Main.scala)
@hrhino
Copy link

hrhino commented Aug 19, 2017

Even smaller:

scala> def Foo(i: Int) = i
Foo: (i: Int)Int

scala> val Foo.Crash = ???
java.lang.NullPointerException
	at scala.tools.nsc.ast.TreeInfo$ValueClass$.$anonfun$valueUnbox$1(TreeInfo.scala:45)
	at scala.tools.nsc.ast.TreeInfo$ValueClass$.valueUnbox(TreeInfo.scala:45)

We are failing to adapt Foo's type (i: Int)Char to a non-method type, duly marking it as error-typed, and then, in a magnificent gesture of clemency, allow the tree to pass unpunished all the way down to posterasure, where it becomes yet another statistic in the shockingly high erroneous tree recidivism rate.

EDIT:

scala> type Q = Foo.type
<console>:12: error: erroneous or inaccessible type
       type Q = Foo.type

I forget... is that better or worse than a compiler crash?

hrhino added a commit to hrhino/scala that referenced this issue Aug 19, 2017
The check for `implicitsEnabled` here seems older even than
that method; it appears to originally have looked at a flag
`reportGeneralErrors`, which seems a reasonable flag if you
want to check whether to report an error. An erroneous tree
that we do not error on, however, can be use as a qualifier
which will not necessarily cause an error until past typer,
when something finally notices the mistake and blows up.

Fixes scala/bug#10474.
@hrhino hrhino self-assigned this Aug 19, 2017
@adriaanm
Copy link
Contributor

Thanks for the report, @maemre, and the fix, @hrhino! Pretty amazing that that loophole's been open-ish

@hrhino hrhino added this to the 2.12.5 milestone Feb 21, 2018
som-snytt added a commit to som-snytt/scala that referenced this issue Feb 21, 2018
@som-snytt
Copy link

Both tests added to the other PR.

@hrhino came so close to the shortest crasher, that it's a shame to mark this as

Duplicates #10731

adriaanm pushed a commit to som-snytt/scala that referenced this issue Mar 9, 2018
The result could never be stable...

TODO: better error message

Tests for scala/bug#10474, scala/bug#10731
adriaanm pushed a commit to som-snytt/scala that referenced this issue Mar 9, 2018
A method is not a value, and thus must somehow be converted
to an expression -- unless we're specifically looking for a method.

We can either insert an application (to implicit args or empty arg list),
or lift to a function by eta-expansion. If those are not possible,
we report an error (unstable tree -- could be refined further).

Tests for scala/bug#10474, scala/bug#10731
@lrytz
Copy link
Member

lrytz commented Mar 12, 2018

Fixed in scala/scala#6273

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants