Skip to content

Good old unsoundness, CCE #4031

@sir-wabbit

Description

@sir-wabbit

http://io.livecode.ch/learn/namin/unsound/scala

object App {
  trait A { type L >: Any}
  def upcast(a: A, x: Any): a.L = x
  lazy val p: A { type L <: Nothing } = p
  def coerce(x: Any): Int = upcast(p, x)

  def main(args: Array[String]): Unit = {
    println(coerce("Uh oh!"))
  }
}

lazy above is not necessary

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
	at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:101)
	at App$.coerce(HelloWorld.scala:5)
	at App$.main(HelloWorld.scala:8)
	at App.main(HelloWorld.scala)

Activity

Blaisorblade

Blaisorblade commented on Feb 22, 2018

@Blaisorblade
Contributor

Without lazy you need null, right? Because otherwise you can't construct a value with p's type.

This looks related to #50 — in this example, it seems that what should be illegal is allowing dependent method upcast to be applied to non-stable argument p.

(If one really wanted it could be legal to allow upcast(p, x) with return type Any (the upper bound of a.L), in the spirit of typing rule (Tapp) in http://drops.dagstuhl.de/opus/volltexte/2017/7276/, but I'm not sure Scala intends to allow this).

self-assigned this
on Feb 22, 2018
odersky

odersky commented on Feb 26, 2018

@odersky
Contributor

I believe the lazy val

lazy val p: A { type L <: Nothing } = p

should not be realizable. We miss a check here.

added a commit that references this issue on Feb 26, 2018

Fix scala#4031: Check arguments of dependent methods for realizability

e8b05e2
Blaisorblade

Blaisorblade commented on Feb 26, 2018

@Blaisorblade
Contributor

Talked with Martin a lot about this and #4036. Turns out Dotty already switched to the refined logic — p is legal but unstable, so applying dependent methods/functions to it requires care.

(If one really wanted it could be legal to allow upcast(p, x) with return type Any (the upper bound of a.L), in the spirit of typing rule (Tapp) in http://drops.dagstuhl.de/opus/volltexte/2017/7276/, but I'm not sure Scala intends to allow this).

There is indeed some logic for it. If method f is dependent and argument e is unstable, f(e) could be rewritten in ANF, and typer produced the same result (a "more general" type). But typer can only approximate whether e is stable (PostTyper is more precise), yet the types it produces can't be refined later. We'll need to resume thinking about this.

added a commit that references this issue on Feb 26, 2018
2910d8a

26 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Development

    Participants

    @Blaisorblade@sir-wabbit@odersky

    Issue actions

      Good old unsoundness, CCE · Issue #4031 · scala/scala3