|
1 |
| -package dotty.tools.backend.jvm |
| 1 | +package dotty.tools |
| 2 | +package backend.jvm |
2 | 3 |
|
3 | 4 | import org.junit.Test
|
4 | 5 | import org.junit.Assert._
|
@@ -161,26 +162,76 @@ class ArrayApplyOptTest extends DottyBytecodeTest {
|
161 | 162 | }
|
162 | 163 |
|
163 | 164 | @Test def testListApplyAvoidsIntermediateArray = {
|
164 |
| - val source = |
165 |
| - """ |
| 165 | + checkApplyAvoidsIntermediateArray("List"): |
| 166 | + """import scala.collection.immutable.{ ::, Nil } |
166 | 167 | |class Foo {
|
167 | 168 | | def meth1: List[String] = List("1", "2", "3")
|
168 |
| - | def meth2: List[String] = |
169 |
| - | new scala.collection.immutable.::("1", new scala.collection.immutable.::("2", new scala.collection.immutable.::("3", scala.collection.immutable.Nil))).asInstanceOf[List[String]] |
| 169 | + | def meth2: List[String] = new ::("1", new ::("2", new ::("3", Nil))) |
| 170 | + |} |
| 171 | + """.stripMargin |
| 172 | + } |
| 173 | + |
| 174 | + @Test def testSeqApplyAvoidsIntermediateArray = { |
| 175 | + checkApplyAvoidsIntermediateArray("Seq"): |
| 176 | + """import scala.collection.immutable.{ ::, Nil } |
| 177 | + |class Foo { |
| 178 | + | def meth1: Seq[String] = Seq("1", "2", "3") |
| 179 | + | def meth2: Seq[String] = new ::("1", new ::("2", new ::("3", Nil))) |
170 | 180 | |}
|
171 | 181 | """.stripMargin
|
| 182 | + } |
| 183 | + |
| 184 | + @Test def testSeqApplyAvoidsIntermediateArray2 = { |
| 185 | + checkApplyAvoidsIntermediateArray("scala.collection.immutable.Seq"): |
| 186 | + """import scala.collection.immutable.{ ::, Seq, Nil } |
| 187 | + |class Foo { |
| 188 | + | def meth1: Seq[String] = Seq("1", "2", "3") |
| 189 | + | def meth2: Seq[String] = new ::("1", new ::("2", new ::("3", Nil))) |
| 190 | + |} |
| 191 | + """.stripMargin |
| 192 | + } |
| 193 | + |
| 194 | + @Test def testSeqApplyAvoidsIntermediateArray3 = { |
| 195 | + checkApplyAvoidsIntermediateArray("scala.collection.Seq"): |
| 196 | + """import scala.collection.immutable.{ ::, Nil }, scala.collection.Seq |
| 197 | + |class Foo { |
| 198 | + | def meth1: Seq[String] = Seq("1", "2", "3") |
| 199 | + | def meth2: Seq[String] = new ::("1", new ::("2", new ::("3", Nil))) |
| 200 | + |} |
| 201 | + """.stripMargin |
| 202 | + } |
172 | 203 |
|
| 204 | + def checkApplyAvoidsIntermediateArray(name: String)(source: String) = { |
173 | 205 | checkBCode(source) { dir =>
|
174 | 206 | val clsIn = dir.lookupName("Foo.class", directory = false).input
|
175 | 207 | val clsNode = loadClassNode(clsIn)
|
176 | 208 | val meth1 = getMethod(clsNode, "meth1")
|
177 | 209 | val meth2 = getMethod(clsNode, "meth2")
|
178 | 210 |
|
179 |
| - val instructions1 = instructionsFromMethod(meth1) |
| 211 | + val instructions1 = instructionsFromMethod(meth1) match |
| 212 | + case instr :+ TypeOp(CHECKCAST, _) :+ TypeOp(CHECKCAST, _) :+ (ret @ Op(ARETURN)) => |
| 213 | + instr :+ ret |
| 214 | + case instr :+ TypeOp(CHECKCAST, _) :+ (ret @ Op(ARETURN)) => |
| 215 | + // List.apply[?A] doesn't, strictly, return List[?A], |
| 216 | + // because it cascades to its definition on IterableFactory |
| 217 | + // where it returns CC[A]. The erasure of that is Object, |
| 218 | + // which is why Erasure's Typer adds a cast to compensate. |
| 219 | + // If we drop that cast while optimising (because using |
| 220 | + // the constructor for :: doesn't require the cast like |
| 221 | + // List.apply did) then then cons construction chain will |
| 222 | + // be typed as ::. |
| 223 | + // Unfortunately the LUB of :: and Nil.type is Product |
| 224 | + // instead of List, so a cast remains necessary, |
| 225 | + // across whatever causes the lub, like `if` or `try` branches. |
| 226 | + // Therefore if we dropping the cast may cause a needed cast |
| 227 | + // to be necessary, we shouldn't drop the cast, |
| 228 | + // which was only motivated by the assert here. |
| 229 | + instr :+ ret |
| 230 | + case instr => instr |
180 | 231 | val instructions2 = instructionsFromMethod(meth2)
|
181 | 232 |
|
182 | 233 | assert(instructions1 == instructions2,
|
183 |
| - "the List.apply method " + |
| 234 | + s"the $name.apply method\n" + |
184 | 235 | diffInstructions(instructions1, instructions2))
|
185 | 236 | }
|
186 | 237 | }
|
|
0 commit comments