-
Notifications
You must be signed in to change notification settings - Fork 21
bug war: type parameters, type aliases, type refinements, type selections #8223
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
Comments
Imported From: https://issues.scala-lang.org/browse/SI-8223?orig=1 |
@retronym said: |
@paulp said: |
@paulp said: def g3 = f2(Array(1))({ val x = new ArrayTC[Int] ; (x: x.type) }) has 2 I am very interested to know what manner of unsoundness could be rendered sound in this fashion. And then, regardless, can't the compiler make that transformation for me? |
@paulp said: def g2 = f2(Array(1))({ val x = arrayTypeClass[Int]; (x: x.type) }) has 2 |
@paulp said: Strangely, or not so strangely, it's essentially the same change as I made for #8177, only in a different spot. Here's the whole change, this time in InstantiateDependentMap. case tp1 if tp1 ne tp1.dealias => apply(tp1.dealias) I really have a great deal of trouble believing this is a soundness issue and not simply compiler bugs. Perhaps someone could demonstrate the unsoundness for me. |
@paulp said: [log typer] InstantiateDependentMap recycling foo.Out: Int
[log typer] InstantiateDependentMap recycling foo.Out: Int
[log typer] InstantiateDependentMap recycling converted.instance.Out: Int
[log typer] InstantiateDependentMap recycling converted.instance.Out: Int
[log typer] InstantiateDependentMap recycling converted.instance.Out: Int
[log typer] InstantiateDependentMap recycling foo.Out: Int
[log typer] InstantiateDependentMap recycling foo.Out: Int
b.scala:26: error: type mismatch;
found : Int(23)
required: si.instance.Out
val v2: Int = indirect(conv(foo))(23) // Fails.
^
b.scala:26: error: type mismatch;
found : si.instance.Out
required: Int
val v2: Int = indirect(conv(foo))(23) // Fails.
^
two errors found In this ticket's test case, we see [log typer] InstantiateDependentMap recycling p.package.SubAlias[tc.type]: p.ViewEnv[tc.A]#SubView
[log typer] InstantiateDependentMap recycling p.package.SubAlias[tc.type]: p.ViewEnv[tc.A]#SubView
[log typer] InstantiateDependentMap recycling p.package.SubAlias[tc.type]: p.ViewEnv[tc.A]#SubView
[log typer] InstantiateDependentMap recycling p.package.SubAlias[tc.type]: p.ViewEnv[tc.A]#SubView
[log typer] InstantiateDependentMap recycling p.package.SubAlias[tc.type]: p.ViewEnv[tc.A]#SubView
[log typer] InstantiateDependentMap recycling p.package.SubAlias[tc.type]: p.ViewEnv[tc.A]#SubView
[log typer] InstantiateDependentMap recycling p.package.intArrayTC.A: Int |
@paulp said: [log typer] InstantiateDependentMap dealias p.package.SubAlias[tc.type] to p.ViewEnv[tc.A]#SubView and discovered: p.ViewEnv[Int]#SubView
[log typer] InstantiateDependentMap dealias p.package.SubAlias[tc.type] to p.ViewEnv[tc.A]#SubView and discovered: p.ViewEnv[Int]#SubView |
@retronym said: |
@paulp said: A type alias like 'type Foo = Bar', how can it be right that there is not even a distinction drawn between it and some nutty type function involving variance and partial type application and nested type members and dependent this and that. And yet, within the compiler pretty much without exception the check which is performed will lump all type aliases into the same bucket. Which means even if one restricts oneself to using type aliases in the soundest and most straightforward fashion, one is treated by the compiler like a type criminal who might rip off the sound system at any moment. Another example of the consequences of all the bundling scala does with its features: say you're staring at some code like this: trait Something[+A]
trait SomethingElse[+B]
trait Foo[+A, B] {
def reverse: Something[A] with SomethingElse[B]
def filter(p: A => Boolean): Something[A] with SomethingElse[B]
def partition(p: A => Boolean): (Something[A] with SomethingElse[B], Something[A] with SomethingElse[B])
} Now any sane person will want to rewrite that something like trait Foo[+A, B] {
private[this] type This = Something[A] with SomethingElse[B]
def reverse: This
def filter(p: A => Boolean): This
def partition(p: A => Boolean): (This, This)
} Naturally it has to be private[this] or you fail the variance check: <console>:11: error: covariant type A occurs in invariant position in type Something[A] with SomethingElse[B] of type This
private type This = Something[A] with SomethingElse[B]
^ Now lucky you are taking on the whole universe of bugs which accompany private[this] for something which has nothing to do with access, members, inheritance. I fully expected it to reject the attempt within a value class because "there is no this there" - maybe it's even a bug that it didn't. But when one just wants less trivially compressible code, all of this is simply language failure. Between that sort of thing and the many bugs like this one which come with type aliases, I honestly believe using the C preprocessor wherever possible would deliver an overall improvement. That's a pretty sad statement. In scala, separate things are never kept separate; many different intentions are multiplexed through the same lossy facilities; static analysis becomes hopeless. Here's a bug I discovered while writing this, in case it's not already among the 1600+ open tickets. scala> final class Foo[+A, B](val x: A) extends AnyVal { private[this] def reverse = ??? }
scala.reflect.internal.Types$TypeError: method reverse$extension in object Foo cannot be accessed in object Foo
at scala.tools.nsc.typechecker.Contexts$Context.issueCommon(Contexts.scala:547)
at scala.tools.nsc.typechecker.Contexts$Context.issue(Contexts.scala:552)
at scala.tools.nsc.typechecker.Infer$Inferencer.issue(Infer.scala:201)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$normalTypedApply$1$1$$anonfun$apply$48.apply(Typers.scala:4465) |
@retronym said: If there are bugs with Now, while its true that you can sometimes work around a bug by adding some tactical dealias-es around the compiler (as in your patch for #8177), that doesn't mean that its the right approach. In #8177, that seemed to be two problems: 1) the assumption that if a type is a subtype of a refinement class it must also be a subclass of the corresponding refinement class symbols; and 2) refinement class symbols of synthetic getters had incoherent owners (and I'll wager at even money that separate compilation could exhibit the same symptom.) The first is easy enough to fix, but the second seemed riskier. For this bug, we have to answer: Why is the restriction on dependent method type instantiation in place? What are the range of unsound programs that it prevents? What are examples of sound programs that it prevents? Can we find a better rule? Oh btw, in: def g2 = f2(Array(1))({ val x = arrayTypeClass[Int]; (x: x.type) }) has 2 I'm a touch surprised that the argument tree is considered stable. I would have expected it to be typed with |
@paulp said: I assume it's a bug. If not I expect to be fascinated by the explanation. |
@paulp said: |
@paulp said: |
@paulp said: scala> def f = ({ val x = "" ; identity[x.type] _ })
f: x.type => x.type forSome { val x: String }
scala> def f = ({ val x = "" ; Set[x.type]() })
f: scala.collection.immutable.Set[_ <: String with Singleton] And naturally I expect it to be stable or I wouldn't have opened the ticket. So if it happened to infer the singleton type, g2 and g3 would work without the intermediate values. |
@adriaanm said: Now, the issue of cycles is problematic and it's not only an implementation detail. Types may depend on (the type checking of) terms. In most cases, though, cycles in the expansion of type aliases indicate actual typing errors. |
@retronym said: |
@adriaanm said (edited on Feb 13, 2014 4:09:58 AM UTC): |
This is related to #8177, but it is not amenable to the workaround of using named type aliases instead of type refinements, because type aliases are equally hopeless.
Notice that f1 and f2 are identical except for where the type selection takes place.
The text was updated successfully, but these errors were encountered: