Suppress warning?

1,484 views
Skip to first unread message

Chapin, Peter @ VTC

unread,
Jul 12, 2012, 2:11:49 PM7/12/12
to scala-l...@googlegroups.com

I’m developing a plugin for the Scala compiler. My plugin adds semantics to constructs that the compiler currently warns about. I’m using the 2.10 compiler (yes, bleeding edge) and it warns about pure expressions “in statement position.” In particular when I do

 

class Example {

  “Hello”

}

 

The naked string literal has no obvious effect and causes the compiler to produce a warning. In my case the plugin notices this construct and does extra special bonus things with it.  What I’m looking for is a way to suppress the warning to reduce noise in my test suite (not to mention for plugin users).

 

I could probably come up with some other way to signal information to the plugin that would be better than this but for the moment I’d rather focus on other more fundamental issues. A quick way to turn off the warning for now would be great. Is there such a way?

 

Peter

 

Simon Ochsenreither

unread,
Jul 12, 2012, 3:49:07 PM7/12/12
to scala-l...@googlegroups.com
I think there is something like -nowarn, which disables all warnings. So this shouldn't be the final solution ... I would suggest looking into the compiler code, maybe a more specific setting is already existing.

Paul Phillips

unread,
Jul 12, 2012, 3:49:22 PM7/12/12
to scala-l...@googlegroups.com
I'll use your email to take another difference of opinion to the people:

The warning you refer to is one of the most useful warnings I know.  It has found many bugs for me, and it's "never" wrong, at least in its current incarnation.  And even so, one can imagine circumstances (or if you are Peter, you don't have to imagine) where the warning is not helpful and you would like to silence it.

I want a generic mechanism for suppressing warnings - specific warnings, or every warning - through a given region.  There are a number of warnings we have that there is no way whatsoever to suppress; there are a bunch more which I think should be on by default, but are not solely because a little noise would come with them and there is no way to suppress it.  So there are two kinds of costs being paid: the warnings we don't hear which we should hear, and the unsuppressable noise from the others.

Can such a suppression mechanism be misused? Can rhetorical questions be answered? The answer in both cases is yes.  Do I think we should all have to pay those costs because a few bad apples will suppress warnings they shouldn't? Will the rhetorical questions stop at one? The answer to both questions is no.

The wontfix ticket I reopened:


Let me be very explicit about my motivation: the reason I want to *suppress* some warnings is that I *like* warnings and I want to hear them clearly.  So I do not cede the "warning high ground" to the "no suppressing warnings" camp, any more than I think spammers love email more than the rest of us.  Too much information is at least as great a threat to efficient compiler/human communication as is too little; greater for sure, in fact, because the quiet side is bounded by zero and the noisy side is unbounded.

I know from experience that it only takes a tiny, tiny dose of build noise before everyone puts on their glazy eyes and looks through it.  The build should be immaculate, so warnings stand out like an overturned cup of cranberry juice on white berber.  Can we not give people the cleaning supplies they need.

Justin du coeur

unread,
Jul 12, 2012, 5:02:26 PM7/12/12
to scala-l...@googlegroups.com
On Thu, Jul 12, 2012 at 3:49 PM, Paul Phillips <pa...@improving.org> wrote:
Let me be very explicit about my motivation: the reason I want to *suppress* some warnings is that I *like* warnings and I want to hear them clearly.  So I do not cede the "warning high ground" to the "no suppressing warnings" camp, any more than I think spammers love email more than the rest of us.  Too much information is at least as great a threat to efficient compiler/human communication as is too little; greater for sure, in fact, because the quiet side is bounded by zero and the noisy side is unbounded.

+1.  Warnings are most useful when there's a way to say, "Yes, this is weird, but I'm doing it intentionally, so get out of my face".  I only use warning-suppression pragmas occasionally, but they're sometimes the only way to get a truly clean build, and clean builds are *always* the goal...

Andreas Flierl

unread,
Jul 12, 2012, 5:31:27 PM7/12/12
to scala-l...@googlegroups.com
Thanks for voicing that concern.

On 12.07.2012, at 21:49, Paul Phillips wrote:
> I want a generic mechanism for suppressing warnings - specific warnings, or every warning - through a given region. There are a number of warnings we have that there is no way whatsoever to suppress; there are a bunch more which I think should be on by default, but are not solely because a little noise would come with them and there is no way to suppress it.

+1

> So there are two kinds of costs being paid: the warnings we don't hear which we should hear, and the unsuppressable noise from the others.
>
> Can such a suppression mechanism be misused? Can rhetorical questions be answered? The answer in both cases is yes. Do I think we should all have to pay those costs because a few bad apples will suppress warnings they shouldn't? Will the rhetorical questions stop at one? The answer to both questions is no.
>
> The wontfix ticket I reopened:
>
> https://issues.scala-lang.org/browse/SI-1781
>
> Let me be very explicit about my motivation: the reason I want to *suppress* some warnings is that I *like* warnings and I want to hear them clearly.

My thoughts exactly.

> So I do not cede the "warning high ground" to the "no suppressing warnings" camp, any more than I think spammers love email more than the rest of us. Too much information is at least as great a threat to efficient compiler/human communication as is too little; greater for sure, in fact, because the quiet side is bounded by zero and the noisy side is unbounded.
>
> I know from experience that it only takes a tiny, tiny dose of build noise before everyone puts on their glazy eyes and looks through it.

That matches what I experienced in the past.

> The build should be immaculate, so warnings stand out like an overturned cup of cranberry juice on white berber. Can we not give people the cleaning supplies they need.

Yes, pleeeease. =^.^=

Erik Osheim

unread,
Jul 12, 2012, 5:34:48 PM7/12/12
to scala-l...@googlegroups.com
On Thu, Jul 12, 2012 at 12:49:22PM -0700, Paul Phillips wrote:
> I want a generic mechanism for suppressing warnings - specific warnings, or
> every warning - through a given region. There are a number of warnings we
> have that there is no way whatsoever to suppress; there are a bunch more
> which I think should be on by default, but are not solely because a little
> noise would come with them and there is no way to suppress it. So there
> are two kinds of costs being paid: the warnings we don't hear which we
> should hear, and the unsuppressable noise from the others.

I think this is a great idea... there are definitely places where I've
had to do some serious contortions to try to avoid warnings which I
knew weren't a problem, but which I didn't want to see.

-- Erik

Paolo Giarrusso

unread,
Jul 19, 2012, 2:25:51 PM7/19/12
to scala-l...@googlegroups.com
+1 also from me. I know two codebases where this problem is very bad because of systematically spurious warnings. -unchecked warnings for typed pattern matches are often stupid to the point of being harmful - fixing the code would not make it prettier. Even though that's not what I use, the best solution is to just not use -unchecked at all, with the obvious problem that valid warnings are hidden. What I do instead is to avoid all warnings, at the cost of obfuscating my source to some extent.
That's what's done by scala-virtualized-tutorial and virtualization-lms-core, both from core Scala hackers (Adriaan Moors and Tiark Rompf).

Two nice examples of false positives from -unchecked:

1.
[warn] /Users/pgiarrusso/Documents/Research/Sorgenti/virtualization-lms-core/src/internal/Expressions.scala:180: non variable type-argument Any in type pattern Iterable[Any] is unchecked since it is eliminated by erasure
[warn]     case ss: Iterable[Any] => ss.toList.flatMap(syms(_))

Erasure allows to check that ss.isInstanceOf[Iterable[_]], but since Iterable is covariant, that implies ss.isInstanceOf[Iterable[Any]], hence the warning is bogus. I don't know the bug report for this.

2. 

[warn] /Users/pgiarrusso/Documents/Research/Sorgenti/scala-virtualized-tutorial/src/org/scala_lang/virtualized/scala/embedscala.scala:297: non variable type-argument Int in type pattern ScalaCodeGen.this.Exp[Int] is unchecked since it is eliminated by erasure
[warn]     case ArrayApply(x: Exp[Array[T]], i: Exp[Int]) =>

Consider that ArrayApply is defined as:
  case class ArrayApply[T](x: Exp[Array[T]], i: Exp[Int]) extends Def[T]
and that the value being scrutinized is of type Def[T], you can convince yourself that the warning is invalid. I think I've seen the bug report about this. The problem, of course, is that once you disable this warning, the code can become silently buggy when you change ArrayApply. But a false positive is useless, so this is only an argument for fixing the warning, not for not having the possibility to disable it.

Best regards

Paul Phillips

unread,
Jul 22, 2012, 12:58:55 AM7/22/12
to scala-l...@googlegroups.com
On Thu, Jul 19, 2012 at 11:25 AM, Paolo Giarrusso <p.gia...@gmail.com> wrote:
Two nice examples of false positives from -unchecked:

Erasure allows to check that ss.isInstanceOf[Iterable[_]], but since Iterable is covariant, that implies ss.isInstanceOf[Iterable[Any]], hence the warning is bogus. I don't know the bug report for this.
 
[warn]     case ArrayApply(x: Exp[Array[T]], i: Exp[Int]) =>

This one was harder because of the structure of the code; it isn't as easy as it should be to see that the pattern corresponds to a known type and the type argument is statically guaranteed.  I was going to have to move more stuff than I'm in a position to move.  It would be easy to fix if the stars aligned a little differently; maybe we'll get there.

Paolo Giarrusso

unread,
Jul 22, 2012, 6:30:00 PM7/22/12
to scala-l...@googlegroups.com
Thanks for taking a look. It sounds impressive that the fix would be "almost easy" - I can just say that fixing this would be extremely cool, at least for people who care about automatic type-correctness verification even in such cases (for instance, researchers like me). Fixing this would not be enough for typechecked code transformation, but it be very helpful (and in my research group we're also slowly working on the rest).

In fact, even nowadays one can get such code to typecheck without warnings - Burak Emir's ECOOP paper  shows how, but nested patterns don't work, and you can't use existing types. And in general, type inference for GADT is hard - although it seems like the hard part is done.
Nowadays, the code you need is along those lines (even though I didn't test this particular example):

case a: ArrayApply[t] =>
  //Here the typechecker knows that T and t are the same.
  //Use a.x and a.i, or bind them to locals:
  val x = a.x
  val i = a.i

When using such syntax, nested pattern matching is not supported, and I need not explain you why that's very bad.
You can't even write
case ArrayApply[t](x, i) =>
which would be needed today for nested pattern matching with type safety. With the current syntax, you'd have to combine two patterns on the same object.

My best attempt (which still failed) was:

object & { def unapply[A](a: A) = Some(a, a) } //read on stackoverflow
...
case (a: ArrayApply[t]) & ArrayApply(x, i) =>
//Here, x has type Exp[Array[_]], and _not_ Exp[Array[t]] as one would hope; that's not easy to fix when & is not a builtin, and would be hard even with this definition of & (note the type):
object & { def unapply[A](a: A): Some[(a.type, a.type)] = Some(a, a) }

Note that this definition is not accepted, but I have no clue why. Not even this:
 def f[A](a: A): a.type = ???
 def f[A](a: A)(b: a.type) = ???
is accepted - why? Do dependent method types not support singleton types?

Cheers,

Paul Phillips

unread,
Jul 22, 2012, 10:02:09 PM7/22/12
to scala-l...@googlegroups.com


On Sun, Jul 22, 2012 at 3:30 PM, Paolo Giarrusso <p.gia...@gmail.com> wrote:
Note that this definition is not accepted, but I have no clue why. Not even this:
 def f[A](a: A): a.type = ???
 def f[A](a: A)(b: a.type) = ???
is accepted - why? Do dependent method types not support singleton types?

We were just talking about this in another thread.  Singleton is bounded by AnyRef.  Jason suggested we make it universal, in which case the above would work.  Failing that, this.

scala> def f[A <: AnyRef](a: A): a.type = ???
f: [A <: AnyRef](a: A)a.type


Paul Phillips

unread,
Jul 22, 2012, 10:26:10 PM7/22/12
to scala-l...@googlegroups.com
On Sun, Jul 22, 2012 at 7:02 PM, Paul Phillips <pa...@improving.org> wrote:
We were just talking about this in another thread.  Singleton is bounded by AnyRef.  Jason suggested we make it universal, in which case the above would work.  Failing that, this.

scala> def f[A <: AnyRef](a: A): a.type = ???
f: [A <: AnyRef](a: A)a.type

Also, the necessary compiler change is three characters (below.) Of course it just ignores the singletoniness of the AnyVals:

scala> def f[A](a: A): a.type = ???
f: [A](a: A)a.type

scala> f(5)
res0: Int = 5

The more interesting move would be to let the singletoniness infuse the AnyVal:


...but that's a separate ambition.


diff --git c/src/compiler/scala/tools/nsc/typechecker/Typers.scala w/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 568a3a9c14..59ba14a266 100644
--- c/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ w/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -5125,7 +5125,7 @@ trait Typers extends Modes with Adaptations with Tags {
 
         case SingletonTypeTree(ref) =>
           val ref1 = checkStable(
-            typed(ref, EXPRmode | QUALmode | (mode & TYPEPATmode), AnyRefClass.tpe))
+            typed(ref, EXPRmode | QUALmode | (mode & TYPEPATmode), AnyClass.tpe))
           tree setType ref1.tpe.resultType
 
         case SelectFromTypeTree(qual, selector) =>

Paolo Giarrusso

unread,
Jul 23, 2012, 1:07:08 AM7/23/12
to scala-l...@googlegroups.com
Ah I see... the error message was even _somewhat_ sensible. Well, not really: AnyRef is not the required type, just the required bound on a's type.
But the hint (see the "possible cause" row below) was so unhelpful that I thought there was some bug or that the problem was elsewhere. If the current behavior is left, I'd argue that the error message should mention what you just said.

$ ~/opt/scala-2.10.0-M5/bin/scala -explaintypes
scala> def f[A](a: A): a.type = ???
<console>:7: error: type mismatch;
 found   : a.type (with underlying type A)
 required: AnyRef
 possible cause: missing arguments for method or constructor
Note that implicit conversions are not applicable because they are ambiguous:
 both method any2stringfmt in object Predef of type (x: Any)scala.runtime.StringFormat
 and method any2stringadd in object Predef of type (x: Any)scala.runtime.StringAdd
 are possible conversion functions from a.type to AnyRef
       def f[A](a: A): a.type = ???
                       ^
a.type <: AnyRef?
false
 
Back to the original point, now I can write this (Scala 2.10.0-M5):

object & { def unapply[A <: AnyRef](a: A): Some[(a.type, a.type)] = Some(a, a) }

(This doesn't typecheck in Scala 2.9.1, even with dependent method types enabled).
But it doesn't work:

trait Exp[+T]
case class ArrayApply[T](arr: Exp[Array[T]], idx: Exp[Int]) extends Exp[T]
scala> def f[T](x: Exp[T]) = x match {
     | case  ArrayApply(x, i) => x
     | }
f: [T](x: Exp[T])Exp[Array[T]]

In this lucky example, the inferred return type is perfect. To get type inference problem we'd need more complex examples.

Anyway, trying to use & does not work:

scala> def f[T <: AnyRef](x: Exp[T]) = x match { case (y: ArrayApply[t]) & ArrayApply(x, i) => x }
<console>:11: error: constructor cannot be instantiated to expected type;
 found   : ArrayApply[T]
 required: <unapply-selector>.type
       def f[T <: AnyRef](x: Exp[T]) = x match { case (y: ArrayApply[t]) & ArrayApply(x, i) => x }
                                                                           ^

Not good. Can something be done? Of course, without singleton types in the extractor the code works (and even in 2.9.1):

scala> object & { def unapply[A <: AnyRef](a: A): Some[(A, A)] = Some(a, a) }
defined module $amp

scala> def f[T <: AnyRef](x: Exp[T]) = x match { case (y: ArrayApply[t]) & ArrayApply(x, i) => x }
f: [T <: AnyRef](x: Exp[T])Exp[Array[T]]
Regards
--
Paolo Giarrusso - Ph.D. Student, Philipps-University Marburg
http://www.informatik.uni-marburg.de/~pgiarrusso/

Paul Phillips

unread,
Jul 23, 2012, 11:28:39 AM7/23/12
to scala-l...@googlegroups.com


On Sun, Jul 22, 2012 at 10:07 PM, Paolo Giarrusso <pgiar...@mathematik.uni-marburg.de> wrote:
Anyway, trying to use & does not work:

scala> def f[T <: AnyRef](x: Exp[T]) = x match { case (y: ArrayApply[t]) & ArrayApply(x, i) => x }
<console>:11: error: constructor cannot be instantiated to expected type;
 found   : ArrayApply[T]
 required: <unapply-selector>.type
       def f[T <: AnyRef](x: Exp[T]) = x match { case (y: ArrayApply[t]) & ArrayApply(x, i) => x }

This is a bug, if you don't mind please open a ticket.

Paolo Giarrusso

unread,
Jul 23, 2012, 12:21:22 PM7/23/12
to scala-l...@googlegroups.com

Paul Phillips

unread,
Jul 27, 2012, 5:31:00 AM7/27/12
to scala-l...@googlegroups.com
On Thu, Jul 19, 2012 at 11:25 AM, Paolo Giarrusso <p.gia...@gmail.com> wrote:
Two nice examples of false positives from -unchecked:

I guess you owe me a soft drink now:


With trunk that prints 11 unchecked warnings, with my branch it prints 6 (fortunately, the expected 6.)

Jason Zaugg

unread,
Jul 27, 2012, 5:49:51 AM7/27/12
to scala-l...@googlegroups.com, adriaa...@epfl.ch
On Fri, Jul 27, 2012 at 11:31 AM, Paul Phillips <pa...@improving.org> wrote:
> I guess you owe me a soft drink now:
>
> https://github.com/paulp/scala/blob/topic/unchecked/test/files/neg/unchecked.scala
> https://github.com/paulp/scala/blob/topic/unchecked/test/files/neg/unchecked.check
>
> With trunk that prints 11 unchecked warnings, with my branch it prints 6
> (fortunately, the expected 6.)

I ran into this one yesterday. The warning isn't emitted in 2.10,
which is a bit of a shame, as it was a proxy for a seemingly absent type error.

// 2.9.2

scala> null match { case Seq(0) => ; case _ => }
<console>:8: error: type mismatch;
found : Int(0)
required: Nothing
null match { case Seq(0) => ; case _ => }
^

scala> case class Foo(a: Any)
defined class Foo

scala> Foo(null) match { case Seq(0) => ; case _ => }
warning: there were 1 unchecked warnings; re-run with -unchecked for details

// 2.10.0-M5

scala> case class Foo(a: Any)
defined class Foo

scala> Foo(null) match { case Seq(0) => ; case _ => }

scala> case class Seqq[A](as: A*)
defined class Seqq

scala> Foo(null) match { case Seqq(0) => ; case _ => }
<console>:12: error: constructor cannot be instantiated to expected type
found : Seqq[A]
required: Foo
Foo(null) match { case Seqq(0) => ; case _ => }
^


Known problem? If not I'll raise a ticket.

-jason

Paul Phillips

unread,
Jul 27, 2012, 6:26:10 AM7/27/12
to scala-l...@googlegroups.com, adriaa...@epfl.ch
On Fri, Jul 27, 2012 at 2:49 AM, Jason Zaugg <jza...@gmail.com> wrote:
I ran into this one yesterday. The warning isn't emitted in 2.10,
which is a bit of a shame, as it was a proxy for a seemingly absent type error.

But  the warning is a bug, even if it is being indirectly helpful.  A warning which admonishes you about type parameters you've never heard of is not a good warning.

Is the type error you're looking for that the extractor should be as demanding as the case class about conforming to the expected type? When the scrutinee and the pattern are different case classes you can exclude the attempt in reasonably good conscience because we don't allow case class inheritance.  My conscience starts to blacken when the pattern is an extractor.

Do you understand the spec well enough to say it's a bug?

Jason Zaugg

unread,
Jul 27, 2012, 7:22:58 AM7/27/12
to scala-l...@googlegroups.com
On Fri, Jul 27, 2012 at 12:26 PM, Paul Phillips <pa...@improving.org> wrote:
> On Fri, Jul 27, 2012 at 2:49 AM, Jason Zaugg <jza...@gmail.com> wrote:
>>
>> I ran into this one yesterday. The warning isn't emitted in 2.10,
>> which is a bit of a shame, as it was a proxy for a seemingly absent type
>> error.
>
> But the warning is a bug, even if it is being indirectly helpful. A
> warning which admonishes you about type parameters you've never heard of is
> not a good warning.

Agreed; I was being whimsical.

> Is the type error you're looking for that the extractor should be as
> demanding as the case class about conforming to the expected type? When the
> scrutinee and the pattern are different case classes you can exclude the
> attempt in reasonably good conscience because we don't allow case class
> inheritance. My conscience starts to blacken when the pattern is an
> extractor.
>
> Do you understand the spec well enough to say it's a bug?

Nope, but I've cc-ed someone who might.

Spec aside, the following looks inconsistent.

-jason


Welcome to Scala version 2.10.0-M5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.
0_25).
Type in expressions to have them evaluated.
Type :help for more information.

scala> trait X[A] { def unapply[A](x: A) = true }

scala> object XInt extends X[Int]
defined module XInt

scala> "" match { case XInt() => }

scala> object XIntDirect { def unapply(x: Int) = true }
defined module XIntDirect

scala> "" match { case XIntDirect() => }
<console>:9: error: scrutinee is incompatible with pattern type;
found : Int
required: String
"" match { case XIntDirect() => }
^

Paul Phillips

unread,
Jul 27, 2012, 7:27:49 AM7/27/12
to scala-l...@googlegroups.com


On Fri, Jul 27, 2012 at 4:22 AM, Jason Zaugg <jza...@gmail.com> wrote:
Agreed; I was being whimsical.

 I'm just a simple cave programmer! I find your whimsy strange and confusing!

Paul Phillips

unread,
Jul 27, 2012, 9:04:23 AM7/27/12
to scala-l...@googlegroups.com
Honk if you dislike warnings.  Can I get a LGTM or even a LATM on one of these?


Time is of the essence! They're drifting, drifting away!

Jason Zaugg

unread,
Jul 28, 2012, 5:29:25 AM7/28/12
to scala-l...@googlegroups.com
On Fri, Jul 27, 2012 at 1:22 PM, Jason Zaugg <jza...@gmail.com> wrote:
> Spec aside, the following looks inconsistent.
>>
> scala> trait X[A] { def unapply[A](x: A) = true }

Scratch that, I screwed up the minimization with that method type param.

The "scrutinee is incompatible with pattern type" error is only issued
if the scrutinee is a final type (final + invariant) [1].

scala> final class M
defined class M

scala> new M match { case Seq() => ; case _ => }
<console>:9: error: scrutinee is incompatible with pattern type;

scala> class M
defined class M

scala> new M match { case Seq() => ; case _ => }

The finality requirement makes sense: A scrutinee statically known
to be a M might be an instance of a subclass that implements Seq.

scala> final class M[+A]
defined class M

scala> new M match { case Seq() => ; case _ => }

The invariance requirement is less obvious. Covariance means we have
to allow for the fact our statically known M[Any] might be M[Int];
so we have to grudgingly allow for this:

scala> class M[+A]
defined class M

scala> object MInt { def unapply(m: M[Int]) = true }
defined module MInt

scala> (new M[Int]: M[Any]) match { case MInt() => 1 ; case _ => 2 }
warning: there were 1 unchecked warnings; re-run with -unchecked for details
res6: Int = 1

scala> (new M[String]: M[Any]) match { case MInt() => 1 ; case _ => 2 }
warning: there were 1 unchecked warnings; re-run with -unchecked for details
res7: Int = 1

If allowing us to wander into unchecked warnings is the only reason for
requiring invariance, could we emit the "scrutinee is incompatible" warning
under -Xlint for scrutinee that are final, but not invariant? (Pity that
wouldn't cover TupleN, which aren't final.)

Long story short: There isn't a bug here, just a reminder that pattern
matching is only a few rungs up the ladder from == and isInstanceOf
in terms of static safety. You are rewarded for declaring your classes
final and invariant.

-jason

[1] https://github.com/scala/scala/blob/186f57/src/compiler/scala/tools/nsc/typechecker/Infer.scala#L1340

Paul Phillips

unread,
Jul 28, 2012, 10:20:00 AM7/28/12
to scala-l...@googlegroups.com


On Sat, Jul 28, 2012 at 2:29 AM, Jason Zaugg <jza...@gmail.com> wrote:
The "scrutinee is incompatible with pattern type" error is only issued
if the scrutinee is a final type (final + invariant) [1].

Indeed, I even remember this trip.  Time to give another shout out to "instantiateTypeVar".

commit a7fd7d6dc257e396cf2cf22a9e0a60c3ce44a992
Author: Paul Phillips <pa...@improving.org>
Date:   1 year, 10 months ago

    Pattern matching on Array types, working for re...
    
    Pattern matching on Array types, working for reals.
    
      def f[T](a: Array[T]) = a match {
        case x: Array[Int]      => x(0)
        case x: Array[Double]   => 2
        // etc.
      }
    
    I'd also like to thank "instantiateTypeVar" for displacing the
    mechanical spiders and giant squid beings which used to fill my
    nightmares. Now that I know true horror, I welcome the squid.
    
    Closes #2755, review by odersky.

Paolo Giarrusso

unread,
Jul 28, 2012, 10:20:59 AM7/28/12
to scala-l...@googlegroups.com, Adriaan Moors
On Fri, Jul 27, 2012 at 11:31 AM, Paul Phillips <pa...@improving.org> wrote:
>
>
> On Thu, Jul 19, 2012 at 11:25 AM, Paolo Giarrusso <p.gia...@gmail.com>
> wrote:
>>
>> Two nice examples of false positives from -unchecked:
>
>
> I guess you owe me a soft drink now:

Cool! I finally had time to take a look, and I'd be glad to pay back my debt :-)

> https://github.com/paulp/scala/blob/topic/unchecked/test/files/neg/unchecked.scala
>
> https://github.com/paulp/scala/blob/topic/unchecked/test/files/neg/unchecked.check
>
> With trunk that prints 11 unchecked warnings, with my branch it prints 6
> (fortunately, the expected 6.)

Yep, cool!
On the same code but a different warning topic, it looks like there's
a missing unreachability warning here: as long as Seq <: List, the
second branch should be unreachable, shouldn't it?

def co1(x: List[Cov[List[Int]]]) = x match {
case _: Seq[Cov[Seq[Any]]] => true // okay
case _ => false
}

So I went ahead and made a bug report:
https://issues.scala-lang.org/browse/SI-6152

Best,

Paul Phillips

unread,
Jul 28, 2012, 10:23:59 AM7/28/12
to scala-l...@googlegroups.com, Adriaan Moors


On Sat, Jul 28, 2012 at 7:20 AM, Paolo Giarrusso <pgiar...@mathematik.uni-marburg.de> wrote:
On the same code but a different warning topic, it looks like there's
a missing unreachability warning here: as long as Seq <: List, the
second branch should be unreachable, shouldn't it?

Nope, not a bug.  There's a single value the first case doesn't cover.  Starts with "n" and ends with "ull..."

Paul Phillips

unread,
Jul 28, 2012, 10:26:43 AM7/28/12
to scala-l...@googlegroups.com, Adriaan Moors
And since I expect it will be your followup question, null is considered for unreachability but not for exhaustiveness checking.  These are the reasonable behaviors, especially since "unreachable code" used to fail the compile (and I think it still should.)

Nils Kilden-Pedersen

unread,
Jul 28, 2012, 10:36:44 AM7/28/12
to scala-l...@googlegroups.com, Adriaan Moors
Shouldn't that only trigger with Xcheck-null enabled?

Paolo Giarrusso

unread,
Jul 28, 2012, 10:55:21 AM7/28/12
to scala-l...@googlegroups.com, Adriaan Moors
On Sat, Jul 28, 2012 at 4:26 PM, Paul Phillips <pa...@improving.org> wrote:
And since I expect it will be your followup question, null is considered for unreachability but not for exhaustiveness checking.  These are the reasonable behaviors, especially since "unreachable code" used to fail the compile (and I think it still should.)

I wasn't going to ask this, just to thank you for the funny way you corrected me :-). But since you explain this strange behavior, let me understand (and find other strange errors on the way).

If I get it, your point is that there is and there should be no warning for either of the following:

case class A()
def f(a: A) = a match {
  case A() => true
}

def f(a: A) = a match {
  case A() => true
  case _ => false
}

because either could be reasonable, depending on whether `f` is supposed to accept `null` or not. In a perfect world, the first one could take A with NotNull, and maybe would have to. However, trying to do so gives a strange error which I don't understand, and which doesn't seem to relate to "NotNull doesn't work yet".

scala> def f(a: A with NotNull) = a match {case A() => true}
<console>:9: error: constructor cannot be instantiated to expected type;
 found   : A
 required: A with NotNull
       def f(a: A with NotNull) = a match {case A() => true}
                                                ^
scala> class B extends A with NotNull
defined class B

scala> case class A()
defined class A

scala> class B extends A with NotNull
defined class B

scala> (new B) match {case A() => true}
<console>:11: error: constructor cannot be instantiated to expected type;
 found   : A
 required: B
              (new B) match {case A() => true}
                                  ^
Why is that? The same happens with `App` instead of `NotNull`.

For comparison, I tried in 2.9.2, this simple code crashes the 2.9.1/2.9.2 compiler:

scala> case class A(); class B extends A with NotNull
exception when typing class B extends $line1.$read#$iw#$iw#A with java.lang.Object with ScalaObject {
  def this(): $line1.$read#$iw#$iw#B = {
    B.super.this();
    ()
  }
}
class Object needs to be a trait to be mixed in in file <console>
scala.tools.nsc.symtab.Types$TypeError: class Object needs to be a trait to be mixed in
        at scala.tools.nsc.typechecker.Contexts$Context.error(Contexts.scala:298)
        at scala.tools.nsc.typechecker.Infer$Inferencer.error(Infer.scala:207)
        at scala.tools.nsc.typechecker.Typers$Typer.validateParentClass$1(Typers.scala:1202)
        at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$validateParentClasses$1.apply(Typers.scala:1236)
        at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$validateParentClasses$1.apply(Typers.scala:1236)
        at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
        at scala.collection.immutable.List.foreach(List.scala:76)
        at scala.tools.nsc.typechecker.Typers$Typer.validateParentClasses(Typers.scala:1236)
[...]
But this crash seems NotNull-specific, since `case class A(); class B extends A with App` just works. So let's try—and get the same strange answer:

scala> case class A(); class B extends A with App
defined class A
defined class B

scala> (new B) match {case A() => true}
<console>:11: error: constructor cannot be instantiated to expected type;
 found   : A
 required: B
              (new B) match {case A() => true}
                                  ^
//Let's check what equality checks say:
scala> new B == A()
res3: Boolean = true

scala> A() == A()
res2: Boolean = true

-- 

Paolo Giarrusso

unread,
Jul 28, 2012, 10:57:00 AM7/28/12
to scala-l...@googlegroups.com, Adriaan Moors
Note that no warning arises; Paul simply explained why the behavior is correct.

Paolo Giarrusso

unread,
Jul 28, 2012, 11:02:35 AM7/28/12
to scala-l...@googlegroups.com
Isn't that a bit too complicated and non-obvious way for checking that
the intersection type in not inhabited? Shouldn't it be possible to
write just that and have a semidecision procedure for it, possibly as
simple as "If T is nothing, it's clearly not inhabited"? This of
course works if intersecting M[X] and Seq[Y] yields M[X] with Seq[Y]
if and only if they are both non-final and at most one is a class (and
maybe something else I forget), and Nothing otherwise.

In the case below, probably the semidecision procedure would still
return "dunno" instead of inhabited, but if somebody ever decides to
fix it, everybody would benefit:

scala> class M[+A](a: A)
defined class M

scala> object MInt { def unapply(m: M[Int]) = true }
defined module MInt

scala> (new M[String]("")) match { case MInt() => 1 ; case _ => 2 }
<console>:11: warning: non variable type-argument Int in type pattern
M[Int] is unchecked since it is eliminated by erasure
(new M[String]("")) match { case MInt() => 1 ; case _ => 2 }
^
res2: Int = 1

Now, note that
a) M[Int] with M[String] = M[Nothing]
b) M[Nothing] is not inhabited, because M[+A] contains a value of type A
c) hence, nothing with type M[String] can be matched by M[Int]

Of course, step b) will be missed today (and maybe forever), but my
point is that at least there'd be hope that other cases which are
missed today would be fixed tomorrow.

Best,

Paul Phillips

unread,
Jul 28, 2012, 11:18:49 AM7/28/12
to scala-l...@googlegroups.com, Adriaan Moors


On Sat, Jul 28, 2012 at 7:55 AM, Paolo Giarrusso <p.gia...@gmail.com> wrote:
scala> (new B) match {case A() => true}
<console>:11: error: constructor cannot be instantiated to expected type;
 found   : A
 required: B
              (new B) match {case A() => true}
                                  ^

This is one of those things I can explain better than I can motivate (which is not to suggest I can explain it well.) A constructor pattern must conform to the expected type of the pattern (SLS 8.1.6.) You have to up-ascript the scrutinee if it doesn't, e.g. ((new B): A). I might have said something more sensible in past discussions of this, but not that I can remember.

martin odersky

unread,
Jul 28, 2012, 11:18:30 AM7/28/12
to scala-l...@googlegroups.com
I don't see the advantage yet. Unchecked, deprecation, and feature
warnings behave the same way. You get a summary line that there were
warnings and you can turn them on selectively if you wish. It seems
this is a good way to go about things. Rather than dropping it for
unchecked, I would prefer to see other categories of warnings behave
the same way.

Cheers

- Martin
--
Martin Odersky
Prof., EPFL and Chairman, Typesafe
PSED, 1015 Lausanne, Switzerland
Tel. EPFL: +41 21 693 6863
Tel. Typesafe: +41 21 691 4967

Nils Kilden-Pedersen

unread,
Jul 28, 2012, 12:27:54 PM7/28/12
to scala-l...@googlegroups.com, Adriaan Moors
On Sat, Jul 28, 2012 at 9:57 AM, Paolo Giarrusso <pgiar...@mathematik.uni-marburg.de> wrote:
On Sat, Jul 28, 2012 at 4:36 PM, Nils Kilden-Pedersen <nil...@gmail.com> wrote:
> On Sat, Jul 28, 2012 at 9:23 AM, Paul Phillips <pa...@improving.org> wrote:
>>
>>
>>
>> On Sat, Jul 28, 2012 at 7:20 AM, Paolo Giarrusso
>> <pgiar...@mathematik.uni-marburg.de> wrote:
>>>
>>> On the same code but a different warning topic, it looks like there's
>>> a missing unreachability warning here: as long as Seq <: List, the
>>> second branch should be unreachable, shouldn't it?
>>
>>
>> Nope, not a bug.  There's a single value the first case doesn't cover.
>> Starts with "n" and ends with "ull..."
>>
>
> Shouldn't that only trigger with Xcheck-null enabled?

Note that no warning arises; Paul simply explained why the behavior is correct.

Ahh, ok.
Reply all
Reply to author
Forward
0 new messages