Skip to content

Commit 22fdca7

Browse files
committed
checking composed aliases/classes arguments
1 parent e1548a4 commit 22fdca7

File tree

5 files changed

+75
-37
lines changed

5 files changed

+75
-37
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4534,22 +4534,24 @@ object Types {
45344534
private var preciseSubstitute: Boolean = false
45354535
private var cachedPrecise: Option[Boolean] = None
45364536
protected[Types] def setPreciseSubstitute(p: Boolean): Unit = preciseSubstitute = p
4537+
private def isPreciseRecur(tp: Type, boringPrecise: Boolean)(using Context): Option[Boolean] = tp match
4538+
case p: TypeParamRef if p == this => Some(boringPrecise)
4539+
case at@AppliedType(_, args) =>
4540+
args
4541+
.lazyZip(at.tyconTypeParams.view.map(p => p.paramPrecise || boringPrecise)).view
4542+
.map(isPreciseRecur).collectFirst {
4543+
case Some(res) => res
4544+
}
4545+
case _ => None
4546+
45374547
override def isPrecise(using Context): Boolean =
45384548
// the param is substituting a precise type or...
45394549
preciseSubstitute || cachedPrecise.getOrElse {
45404550
val precise =
45414551
// the param itself is annotated as precise or the param is first introduced
45424552
// in a precise position of an applied type argument
4543-
binder.paramPrecises(paramNum) || binder.resType.paramInfoss.view.flatten.flatMap {
4544-
case p: TypeParamRef if p == this => Some(false)
4545-
case at @ AppliedType(_, args) =>
4546-
val paramIdx = args.indexOf(this)
4547-
val syms = at.tyconTypeParams
4548-
if syms.isEmpty then None
4549-
else if paramIdx >= 0 then Some(syms(paramIdx).paramPrecise)
4550-
else None
4551-
case _ => None
4552-
}.headOption.getOrElse(false)
4553+
binder.paramPrecises(paramNum) ||
4554+
binder.resType.paramInfoss.view.flatten.flatMap(isPreciseRecur(_, false)).headOption.getOrElse(false)
45534555
cachedPrecise = Some(precise)
45544556
precise
45554557
} ||

compiler/src/dotty/tools/dotc/typer/PreciseChecker.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ object PreciseChecker:
1212
def check(tparams: List[tpd.TypeDef], applied: Type, mode : Mode)(using Context): Unit =
1313
applied match
1414
case tpe@AppliedType(_, args) =>
15+
args.foreach(check(tparams, _, mode)) //recursively checking applied params
1516
val appliedParamPreciseList = tpe.tyconTypeParams.map(_.paramPrecise)
1617
val tdefParamPreciseMap = tparams.view.map(p => (p.name, p.symbol.paramPrecise)).toMap
1718

tests/neg/precise-alias-extends.check

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,27 @@
3434
48 | type FooConAlias[-A] = FooCon[A] // error
3535
| ^^
3636
| imprecise type parameter A occurs in precise position in preciseTypeAliasExtendLessPrecise.FooCon[A]
37-
-- Error: tests/neg/precise-alias-extends.scala:58:16 ------------------------------------------------------------------
38-
58 | type Less[T] <: PBox[T] // error
37+
-- Error: tests/neg/precise-alias-extends.scala:55:17 ------------------------------------------------------------------
38+
55 | type FooAlias1[A] = Box[Foo[A]] // error
39+
| ^
40+
| imprecise type parameter A occurs in precise position in preciseTypeAliasComposition.Foo[A]
41+
-- Error: tests/neg/precise-alias-extends.scala:59:26 ------------------------------------------------------------------
42+
59 | type BoxAlias2[@precise A] = Foo[Box[A]] // error
43+
| ^^^^^^^^^^
44+
| precise type parameter A occurs in imprecise position in preciseTypeAliasComposition.Box[A]
45+
-- Error: tests/neg/precise-alias-extends.scala:69:16 ------------------------------------------------------------------
46+
69 | type Less[T] <: PBox[T] // error
3947
| ^
4048
| imprecise type parameter T occurs in precise position in preciseTypeBounds.PBox[T]
41-
-- Error: tests/neg/precise-alias-extends.scala:63:25 ------------------------------------------------------------------
42-
63 | type More[@precise T] >: Box[T] // error
49+
-- Error: tests/neg/precise-alias-extends.scala:74:25 ------------------------------------------------------------------
50+
74 | type More[@precise T] >: Box[T] // error
4351
| ^^^^^^^^^^
4452
| precise type parameter T occurs in imprecise position in preciseTypeBounds.Box[T]
45-
-- Error: tests/neg/precise-alias-extends.scala:67:21 ------------------------------------------------------------------
46-
67 | opaque type Less[T] <: PBox[T] = PBox[T] // error
53+
-- Error: tests/neg/precise-alias-extends.scala:78:21 ------------------------------------------------------------------
54+
78 | opaque type Less[T] <: PBox[T] = PBox[T] // error
4755
| ^
4856
| imprecise type parameter T occurs in precise position in preciseTypeBounds.PBox[T]
49-
-- Error: tests/neg/precise-alias-extends.scala:68:30 ------------------------------------------------------------------
50-
68 | opaque type More[@precise T] <: Box[T] = Box[T] // error
57+
-- Error: tests/neg/precise-alias-extends.scala:79:30 ------------------------------------------------------------------
58+
79 | opaque type More[@precise T] <: Box[T] = Box[T] // error
5159
| ^^^^^^^^^^
5260
| precise type parameter T occurs in imprecise position in preciseTypeBounds.Box[T]

tests/neg/precise-alias-extends.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ object preciseTypeAliasExtendLessPrecise:
4848
type FooConAlias[-A] = FooCon[A] // error
4949

5050

51+
object preciseTypeAliasComposition:
52+
trait Foo[@precise T]
53+
trait Box[T]
54+
55+
type FooAlias1[A] = Box[Foo[A]] // error
56+
type FooAlias2[A] = Foo[Box[A]]
57+
58+
type BoxAlias1[@precise A] = Box[Foo[A]]
59+
type BoxAlias2[@precise A] = Foo[Box[A]] // error
60+
61+
5162
object preciseTypeBounds:
5263
class Box[T]
5364
class PBox[@precise T]

tests/neg/precise-typecheck.scala

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ object preciseDefs:
2525
final val list1hi = id(1 :: "hi" :: Nil)
2626
val list1hiTest: List[1 | "hi"] = list1hi
2727

28-
val c : Boolean = ???
28+
val c: Boolean = ???
2929
val ifVal = idBox(if c then 2 else 3)
3030
val ifValTest: Box[2 | 3] = ifVal
3131

3232
def huge[@precise T1, T2, T3, @precise T4, @precise T5](
33-
t1: T1, t2 : T2, r : Int
34-
)(t3: T3, r2: Int, t4: T4)(t5 : T5*): Box[(T1, T2, T3, T4, T5)] = ???
33+
t1: T1, t2: T2, r: Int
34+
)(t3: T3, r2: Int, t4: T4)(t5: T5*): Box[(T1, T2, T3, T4, T5)] = ???
3535

3636
val h1 = huge((1, 2), (3, 4), 5)((6, 7), 8, (9, 10))(11, 12)
3737
val h1Test: Box[((1, 2), (Int, Int), (Int, Int), (9, 10), 11 | 12)] = h1
@@ -44,11 +44,11 @@ object preciseUpperBound:
4444

4545

4646
object preciseDepArgs:
47-
def same[@precise T](x: T, y: T) : Box[T] = ???
47+
def same[@precise T](x: T, y: T): Box[T] = ???
4848
final val sameVal = same(1, 2)
4949
val sameValTest: Box[1 | 2] = sameVal
5050

51-
def sameVarArgs[@precise T](a: T*) : Box[T] = ???
51+
def sameVarArgs[@precise T](a: T*): Box[T] = ???
5252
final val sameVal123hi = sameVarArgs(1, 2, 3, "hi")
5353
val sameVal123hiTest: Box[1 | 2 | 3 | "hi"] = sameVal123hi
5454

@@ -67,7 +67,7 @@ object preciseDepArgs:
6767

6868

6969
object preciseExtendClassArgs:
70-
class Foo[@precise T](val value : T)
70+
class Foo[@precise T](val value: T)
7171

7272
object Bar extends Foo(5)
7373
val barTest: 5 = Bar.value
@@ -77,7 +77,7 @@ object preciseExtendClassArgs:
7777

7878

7979
object preciseEnums:
80-
enum Foo[@precise T](val value : T):
80+
enum Foo[@precise T](val value: T):
8181
case Bar extends Foo(5)
8282
case Baz extends Foo((1, 2))
8383

@@ -105,10 +105,10 @@ object preciseDefaultValues:
105105

106106

107107
object preciseGivens:
108-
given one : 1 = 1
109-
def fetch[@precise T <: Int](using T) : Box[T] = ???
108+
given one: 1 = 1
109+
def fetch[@precise T <: Int](using T): Box[T] = ???
110110
val f = fetch
111-
val fTest : Box[1] = f
111+
val fTest: Box[1] = f
112112

113113
class PreciseBox[@precise T]
114114
given [T]: PreciseBox[T] with {}
@@ -117,7 +117,7 @@ object preciseGivens:
117117
val c1 = check(1)
118118
val c1Test: Box[Int] = c1
119119

120-
def foo[@precise T : Box](arg: T): Box[T] = summon[Box[T]]
120+
def foo[@precise T: Box](arg: T): Box[T] = summon[Box[T]]
121121
object fooTest:
122122
given Box[1] = new Box[1](1)
123123
val x = foo(1)
@@ -179,10 +179,26 @@ object preciseCovariance:
179179
val fbic12Test: Inv[Int, 2] = fbic12
180180

181181

182+
object preciseCovariantComposition:
183+
object direct:
184+
class BoxC[@precise +A]
185+
def fromBox[B](x: Box[BoxC[B]]): BoxC[B] = ???
186+
val bb1: Box[BoxC[1]] = ???
187+
val frombb1 = fromBox(bb1)
188+
val frombb1Test: BoxC[1] = frombb1
189+
190+
object boring:
191+
class BoxC[@precise +A]
192+
def fromBox[B](x: BoxC[(1, B)]): BoxC[B] = ???
193+
val b1: BoxC[(1, 1)] = ???
194+
val fromb1 = fromBox(b1)
195+
val fromb1Test: BoxC[1] = fromb1
196+
197+
182198
object preciseCovariantOpaque:
183199
opaque type BoxC[@precise +A] = A
184200
def fromBox[B <: Any](x: BoxC[B]): BoxC[B] = x
185-
val b1 : BoxC[1] = ???
201+
val b1: BoxC[1] = ???
186202
val b11 = fromBox(b1)
187203
val b11Test: BoxC[1] = b11
188204

@@ -264,14 +280,14 @@ object preciseCovarianceWithCompiletimeOps:
264280
import compiletime.ops.int.+
265281
class Inlined[@precise +T <: Int]
266282
extension [T <: Int](lhs: Inlined[T])
267-
def inc : Inlined[T + 1] = ???
283+
def inc: Inlined[T + 1] = ???
268284

269285
val i1 = Inlined[1]
270286
val i3: Inlined[3] = i1.inc.inc
271287

272288

273289
object preciseByName:
274-
def id[@precise T](t : => T): Box[T] = ???
290+
def id[@precise T](t: => T): Box[T] = ???
275291
val x = id(1)
276292
val xTest: Box[1] = x
277293
val y = id((1, 2))
@@ -280,7 +296,7 @@ object preciseByName:
280296

281297
object preciseFuncX:
282298
object func0:
283-
def id[@precise T](t : () => T): Box[T] = ???
299+
def id[@precise T](t: () => T): Box[T] = ???
284300
val x = id(() => 1)
285301
val xTest: Box[1] = x
286302
val y = id(() => (1, 2))
@@ -357,9 +373,9 @@ object preciseImplicitConversion:
357373

358374

359375
object preciseImplicitConversionNewStyle:
360-
given toBoxFromTuple[@precise T <: Tuple] : Conversion[T, Box[T]] = Box(_)
361-
given toBoxFromInt[@precise T <: Int] : Conversion[T, Box[T]] = Box(_)
362-
given toBoxFromString[T <: String] : Conversion[T, Box[T]] = Box(_)
376+
given toBoxFromTuple[@precise T <: Tuple]: Conversion[T, Box[T]] = Box(_)
377+
given toBoxFromInt[@precise T <: Int]: Conversion[T, Box[T]] = Box(_)
378+
given toBoxFromString[T <: String]: Conversion[T, Box[T]] = Box(_)
363379
def box[T1, T2, T3, @precise T4, T5](
364380
b1: Box[T1], b2: Box[T2], r: Int, b3: Box[T3]
365381
)(
@@ -375,7 +391,7 @@ object preciseImplicitConversionNewStyle:
375391

376392
object precisePolymorphicTypesAndValues:
377393
type Id1 = [@precise T] => T => Box[T]
378-
val id1Check: Id1 = [T] => (t : T) => Box(t) // error
394+
val id1Check: Id1 = [T] => (t: T) => Box(t) // error
379395

380396
type Id2 = [T] => T => Box[T]
381397
val id2Check: Id2 = [@precise T] => (t: T) => Box(t) // error

0 commit comments

Comments
 (0)