Scala Programming Language
  1. Scala Programming Language
  2. SI-140

Multiple assignment does not do correct typing

    Details

    • Type: Improvement Improvement
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: 2.12.0-M1
    • Component/s: Misc Compiler
    • Labels:
      None
    • Environment:

      crash compiler multiple assignment

      Description

      The following code should not compile:

      val (is: Option[String], not: Option[String]) = ("a", "b") match {
        case ("b", _) => (Some("Dog"), None)
        case _ => (Some((1,2)), Some("Dog"))
      }
      
      is.foreach(v => println(v.length))
      

      Note that 'is' is typed as an Option[String], but it is assigned either Option[String] or Option[(Int, Int)]

      This leads to a runtime error.

        Issue Links

          Activity

          Hide
          Daniel Sobral added a comment -

          While this has been compared to SI-900, I don't think they are really about the same issue. I see this much in the same way as match statement error to the effect the match is impossible.

          The semantics I'd personally like to see is: if the inferred/ascribed type cannot satisfy the pre-erasure type of pattern match statements (valid for val, for and match), return an error.

          Just to compare and combine with SI-900, these are things I'd expect:

          for (i: Int <- List('symbol, "string", true)) yield i // compiles
          for (i: Int <- List(false, true, false)) yield i // error

          Show
          Daniel Sobral added a comment - While this has been compared to SI-900 , I don't think they are really about the same issue. I see this much in the same way as match statement error to the effect the match is impossible. The semantics I'd personally like to see is: if the inferred/ascribed type cannot satisfy the pre-erasure type of pattern match statements (valid for val, for and match), return an error. Just to compare and combine with SI-900 , these are things I'd expect: for (i: Int <- List('symbol, "string", true)) yield i // compiles for (i: Int <- List(false, true, false)) yield i // error
          Hide
          Daniel Sobral added a comment -

          Reformatted the code:

          for (i: Int <- List('symbol, "string", true)) yield i // compiles 
          for (i: Int <- List(false, true, false)) yield i // error
          
          Show
          Daniel Sobral added a comment - Reformatted the code: for (i: Int <- List('symbol, "string", true)) yield i // compiles for (i: Int <- List(false, true, false)) yield i // error
          Hide
          Simon Ochsenreither added a comment -

          The first two examples crash the compiler:

          scala> val (is: Option[String], not: Option[String]) = ("a", "b") match {
               |   case ("b", _) => (Some("Dog"), None)
               |   case _ => (Some((1,2)), Some("Dog"))
               | }
          java.lang.Error: symbol value x$$1 does not exist in <init>
          	at scala.tools.nsc.symtab.SymbolTable.abort(SymbolTable.scala:35)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:1027)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.genLoadQualifier(GenICode.scala:1175)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:921)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.genLoadQualifier(GenICode.scala:1175)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:738)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genStat(GenICode.scala:163)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$genStat$$1.apply(GenICode.scala:143)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$genStat$$1.apply(GenICode.scala:143)
          	at scala.collection.LinearSeqOptimized$$class.foldLeft(LinearSeqOptimized.scala:111)
          	at scala.collection.immutable.List.foldLeft(List.scala:45)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.genStat(GenICode.scala:143)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:1052)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:114)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69)
          	at scala.collection.LinearSeqOptimized$$class.foreach(LinearSeqOptimized.scala:59)
          	at scala.collection.immutable.List.foreach(List.scala:45)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:69)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:136)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:88)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69)
          	at scala.collection.LinearSeqOptimized$$class.foreach(LinearSeqOptimized.scala:59)
          	at scala.collection.immutable.List.foreach(List.scala:45)
          
          scala> val (tis, not: Option[String]) = ("a", "b") match {
               |   case ("b", _) => (Some("Dog"), None)
               |   case _ => (Some((1,2)), Some("Dog"))
               | }
          java.lang.Error: symbol value x$$1 does not exist in <init>
          	at scala.tools.nsc.symtab.SymbolTable.abort(SymbolTable.scala:35)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:1027)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.genLoadQualifier(GenICode.scala:1175)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:921)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.genLoadQualifier(GenICode.scala:1175)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:738)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genStat(GenICode.scala:163)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$genStat$$1.apply(GenICode.scala:143)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$genStat$$1.apply(GenICode.scala:143)
          	at scala.collection.LinearSeqOptimized$$class.foldLeft(LinearSeqOptimized.scala:111)
          	at scala.collection.immutable.List.foldLeft(List.scala:45)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.genStat(GenICode.scala:143)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:1052)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:114)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69)
          	at scala.collection.LinearSeqOptimized$$class.foreach(LinearSeqOptimized.scala:59)
          	at scala.collection.immutable.List.foreach(List.scala:45)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:69)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:136)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:88)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69)
          	at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69)
          	at scala.collection.LinearSeqOptimized$$class.foreach(LinearSeqOptimized.scala:59)
          	at scala.collection.immutable.List.foreach(List.scala:45)
          

          and the last two don't compile:

          scala> for (i: Int <- List('symbol, "string", true)) yield i // compiles
          <console>:8: error: type mismatch;
           found   : (Int) => Int
           required: (Any) => ?
                 for (i: Int <- List('symbol, "string", true)) yield i // compiles
                             ^
          
          scala> for (i: Int <- List(false, true, false)) yield i // error
          <console>:8: error: type mismatch;
           found   : (Int) => Int
           required: (Boolean) => ?
                 for (i: Int <- List(false, true, false)) yield i // error
                             ^
          
          Show
          Simon Ochsenreither added a comment - The first two examples crash the compiler: scala> val (is: Option[String], not: Option[String]) = ("a", "b") match { | case ("b", _) => (Some("Dog"), None) | case _ => (Some((1,2)), Some("Dog")) | } java.lang.Error: symbol value x$$1 does not exist in <init> at scala.tools.nsc.symtab.SymbolTable.abort(SymbolTable.scala:35) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:1027) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.genLoadQualifier(GenICode.scala:1175) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:921) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.genLoadQualifier(GenICode.scala:1175) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:738) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genStat(GenICode.scala:163) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$genStat$$1.apply(GenICode.scala:143) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$genStat$$1.apply(GenICode.scala:143) at scala.collection.LinearSeqOptimized$$class.foldLeft(LinearSeqOptimized.scala:111) at scala.collection.immutable.List.foldLeft(List.scala:45) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.genStat(GenICode.scala:143) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:1052) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:114) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69) at scala.collection.LinearSeqOptimized$$class.foreach(LinearSeqOptimized.scala:59) at scala.collection.immutable.List.foreach(List.scala:45) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:69) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:136) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:88) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69) at scala.collection.LinearSeqOptimized$$class.foreach(LinearSeqOptimized.scala:59) at scala.collection.immutable.List.foreach(List.scala:45) scala> val (tis, not: Option[String]) = ("a", "b") match { | case ("b", _) => (Some("Dog"), None) | case _ => (Some((1,2)), Some("Dog")) | } java.lang.Error: symbol value x$$1 does not exist in <init> at scala.tools.nsc.symtab.SymbolTable.abort(SymbolTable.scala:35) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:1027) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.genLoadQualifier(GenICode.scala:1175) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:921) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.genLoadQualifier(GenICode.scala:1175) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:738) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genStat(GenICode.scala:163) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$genStat$$1.apply(GenICode.scala:143) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$genStat$$1.apply(GenICode.scala:143) at scala.collection.LinearSeqOptimized$$class.foldLeft(LinearSeqOptimized.scala:111) at scala.collection.immutable.List.foldLeft(List.scala:45) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.genStat(GenICode.scala:143) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.scala$$tools$$nsc$$backend$$icode$$GenICode$$ICodePhase$$$$genLoad(GenICode.scala:1052) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:114) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69) at scala.collection.LinearSeqOptimized$$class.foreach(LinearSeqOptimized.scala:59) at scala.collection.immutable.List.foreach(List.scala:45) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:69) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:136) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase.gen(GenICode.scala:88) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69) at scala.tools.nsc.backend.icode.GenICode$$ICodePhase$$$$anonfun$$gen$$1.apply(GenICode.scala:69) at scala.collection.LinearSeqOptimized$$class.foreach(LinearSeqOptimized.scala:59) at scala.collection.immutable.List.foreach(List.scala:45) and the last two don't compile: scala> for (i: Int <- List('symbol, "string", true)) yield i // compiles <console>:8: error: type mismatch; found : (Int) => Int required: (Any) => ? for (i: Int <- List('symbol, "string", true)) yield i // compiles ^ scala> for (i: Int <- List(false, true, false)) yield i // error <console>:8: error: type mismatch; found : (Int) => Int required: (Boolean) => ? for (i: Int <- List(false, true, false)) yield i // error ^
          Hide
          A. P. Marki added a comment -

          For those cats not killed by curiosity,

          scala> val (is: Option[String], not: Option[String]) = ("a", "b") match {
            case ("b", _) => (Some("Dog"), None)
            case _ => (Some((1,2)), Some("Dog"))
          }
          <console>:7: warning: non-variable type argument String in type pattern Option[String] is unchecked since it is eliminated by erasure
                 val (is: Option[String], not: Option[String]) = ("a", "b") match {
                          ^
          <console>:7: error: pattern type is incompatible with expected type;
           found   : Option[String]
           required: Some[java.io.Serializable]
                 val (is: Option[String], not: Option[String]) = ("a", "b") match {
                          ^
          
          Show
          A. P. Marki added a comment - For those cats not killed by curiosity, scala> val (is: Option[String], not: Option[String]) = ("a", "b") match { case ("b", _) => (Some("Dog"), None) case _ => (Some((1,2)), Some("Dog")) } <console>:7: warning: non-variable type argument String in type pattern Option[String] is unchecked since it is eliminated by erasure val (is: Option[String], not: Option[String]) = ("a", "b") match { ^ <console>:7: error: pattern type is incompatible with expected type; found : Option[String] required: Some[java.io.Serializable] val (is: Option[String], not: Option[String]) = ("a", "b") match { ^
          Hide
          Grzegorz Kossakowski added a comment -

          Unassigning and rescheduling to M7 as previous deadline was missed.

          Show
          Grzegorz Kossakowski added a comment - Unassigning and rescheduling to M7 as previous deadline was missed.

            People

            • Assignee:
              Adriaan Moors
              Reporter:
              David Pollak
              TracCC:
              Alex Cruise, Daniel Sobral, Eric Torreborre, Erik Engbrecht, Ismael Juma, Paul Phillips, Seth Tisue, Simon Ochsenreither
            • Votes:
              2 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:

                Development