@@ -28,7 +28,9 @@ import org.scalajs.logging._
28
28
import org .scalajs .junit .async ._
29
29
30
30
import org .scalajs .linker .interface ._
31
+ import org .scalajs .linker .interface .unstable .IRFileImpl
31
32
import org .scalajs .linker .standard ._
33
+ import org .scalajs .linker .frontend .Refiner
32
34
33
35
import org .scalajs .linker .testutils ._
34
36
import org .scalajs .linker .testutils .TestIRBuilder ._
@@ -306,46 +308,111 @@ class IRCheckerTest {
306
308
}
307
309
}
308
310
311
+ def immutableFieldAssignTestClassDefs (parent : Boolean ): Seq [ClassDef ] = {
312
+ val ctorBodyUnderTest =
313
+ Assign (Select (thisFor(" Bar" ), FieldName (" Foo" , " fooFld" ))(IntType ), int(1 ))
314
+
315
+ Seq (
316
+ classDef(
317
+ " Foo" ,
318
+ superClass = Some (ObjectClass ),
319
+ fields = List (FieldDef (EMF , FieldName (" Foo" , " fooFld" ), NON , IntType ))
320
+ ),
321
+ classDef(
322
+ " Bar" ,
323
+ superClass = Some (if (parent) " Foo" else ObjectClass ),
324
+ methods = List (
325
+ MethodDef (
326
+ EMF .withNamespace(MemberNamespace .Constructor ),
327
+ NoArgConstructorName , NON , Nil , VoidType ,
328
+ Some (ctorBodyUnderTest))(EOH , UNV )
329
+ )
330
+ ),
331
+ mainTestClassDef(New (" Bar" , NoArgConstructorName , Nil ))
332
+ )
333
+ }
334
+
335
+ @ Test
336
+ def noImmutableAssignNonParent (): AsyncResult = await {
337
+ val classDefs = immutableFieldAssignTestClassDefs(parent = false )
338
+
339
+ for {
340
+ log <- testLinkIRErrors(classDefs, MainTestModuleInitializers , postOptimizer = true )
341
+ } yield {
342
+ log.assertContainsError(" Foo expected but Bar! found for tree of type org.scalajs.ir.Trees$This" )
343
+ }
344
+ }
345
+
346
+ @ Test
347
+ def allowImmutableAssignParent (): AsyncResult = await {
348
+ val classDefs = immutableFieldAssignTestClassDefs(parent = true )
349
+ testLinkNoIRError(classDefs, MainTestModuleInitializers , postOptimizer = true )
350
+ }
351
+
309
352
}
310
353
311
354
object IRCheckerTest {
312
355
def testLinkNoIRError (classDefs : Seq [ClassDef ],
313
- moduleInitializers : List [ModuleInitializer ])(
356
+ moduleInitializers : List [ModuleInitializer ],
357
+ postOptimizer : Boolean = false )(
314
358
implicit ec : ExecutionContext ): Future [Unit ] = {
315
- link(classDefs, moduleInitializers, new ScalaConsoleLogger (Level .Error ))
359
+ link(classDefs, moduleInitializers, new ScalaConsoleLogger (Level .Error ), postOptimizer )
316
360
}
317
361
318
362
def testLinkIRErrors (classDefs : Seq [ClassDef ],
319
- moduleInitializers : List [ModuleInitializer ])(
363
+ moduleInitializers : List [ModuleInitializer ],
364
+ postOptimizer : Boolean = false )(
320
365
implicit ec : ExecutionContext ): Future [LogLines ] = {
321
366
322
367
val logger = new CapturingLogger
323
368
324
- link(classDefs, moduleInitializers, logger).transform {
369
+ link(classDefs, moduleInitializers, logger, postOptimizer ).transform {
325
370
case Success (_) => Failure (new AssertionError (" IR checking did not fail" ))
326
371
case Failure (_) => Success (logger.allLogLines)
327
372
}
328
373
}
329
374
330
375
private def link (classDefs : Seq [ClassDef ],
331
376
moduleInitializers : List [ModuleInitializer ],
332
- logger : Logger )(implicit ec : ExecutionContext ): Future [Unit ] = {
333
- val config = StandardConfig ()
377
+ logger : Logger , postOptimizer : Boolean )(
378
+ implicit ec : ExecutionContext ): Future [Unit ] = {
379
+ val baseConfig = StandardConfig ()
334
380
.withCheckIR(true )
335
381
.withOptimizer(false )
336
- val linkerFrontend = StandardLinkerFrontend (config)
382
+
383
+ val config = {
384
+ /* Disable RuntimeLongs to workaround the Refiner disabling IRChecks in this case.
385
+ * TODO: Remove once we run IRChecks post optimizer all the time.
386
+ */
387
+ if (postOptimizer) baseConfig.withESFeatures(_.withAllowBigIntsForLongs(true ))
388
+ else baseConfig
389
+ }
337
390
338
391
val noSymbolRequirements = SymbolRequirement
339
392
.factory(" IRCheckerTest" )
340
393
.none()
341
394
342
395
TestIRRepo .minilib.flatMap { stdLibFiles =>
343
- val irFiles = (
396
+ if (postOptimizer) {
397
+ val refiner = new Refiner (CommonPhaseConfig .fromStandardConfig(config), checkIR = true )
398
+
399
+ Future .traverse(stdLibFiles)(f => IRFileImpl .fromIRFile(f).tree).flatMap { stdLibClassDefs =>
400
+ val allClassDefs = (
401
+ stdLibClassDefs ++
402
+ classDefs
403
+ )
404
+
405
+ refiner.refine(allClassDefs.map(c => (c, UNV )), moduleInitializers,
406
+ noSymbolRequirements, logger)
407
+ }
408
+ } else {
409
+ val linkerFrontend = StandardLinkerFrontend (config)
410
+ val irFiles = (
344
411
stdLibFiles ++
345
412
classDefs.map(MemClassDefIRFile (_))
346
- )
347
-
348
- linkerFrontend.link(irFiles, moduleInitializers, noSymbolRequirements, logger)
413
+ )
414
+ linkerFrontend.link(irFiles, moduleInitializers, noSymbolRequirements, logger)
415
+ }
349
416
}.map(_ => ())
350
417
}
351
418
}
0 commit comments