Skip to content

Commit b964de9

Browse files
committed
Warn when a non-fully-dependent class is used with applied constructor types
1 parent 5d58646 commit b964de9

File tree

5 files changed

+27
-18
lines changed

5 files changed

+27
-18
lines changed

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
224224
case ExtensionHasDefaultID // errorNumber: 208
225225
case FormatInterpolationErrorID // errorNumber: 209
226226
case ValueClassCannotExtendAliasOfAnyValID // errorNumber: 210
227-
case PointlessAppliedConstructorTypeID // errorNumber: 211
227+
case OnlyFullyDependentAppliedConstructorTypeID // errorNumber: 211
228+
case PointlessAppliedConstructorTypeID // errorNumber: 212
228229

229230
def errorNumber = ordinal - 1
230231

compiler/src/dotty/tools/dotc/reporting/messages.scala

+7
Original file line numberDiff line numberDiff line change
@@ -3471,3 +3471,10 @@ final class PointlessAppliedConstructorType(tpt: untpd.Tree, args: List[untpd.Tr
34713471
|If you want to track a precise type of any of the class parameters, make sure to mark the parameter as `tracked`.
34723472
|Otherwise, you can safely remove the argument list from the type.
34733473
|"""
3474+
3475+
final class OnlyFullyDependentAppliedConstructorType()(using Context)
3476+
extends TypeMsg(OnlyFullyDependentAppliedConstructorTypeID):
3477+
override protected def msg(using Context): String =
3478+
i"Applied constructor type can only be used with classes that only have tracked parameters"
3479+
3480+
override protected def explain(using Context): String = ""

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

+4
Original file line numberDiff line numberDiff line change
@@ -1722,6 +1722,10 @@ trait Applications extends Compatibility {
17221722
def apply(tp: Type) = mapOver(tp.widenSkolem)
17231723
val preciseTp = widenSkolemsMap(tree1.tpe)
17241724
val classTp = typedType(tpt).tpe
1725+
def classSymbolHasOnlyTrackedParameters =
1726+
classTp.classSymbol.primaryConstructor.paramSymss.flatten.filter(_.isTerm).forall(_.is(Tracked))
1727+
if !preciseTp.isError && !classSymbolHasOnlyTrackedParameters then
1728+
report.warning(OnlyFullyDependentAppliedConstructorType(), tree.srcPos)
17251729
if !preciseTp.isError && (preciseTp frozen_=:= classTp) then
17261730
report.warning(PointlessAppliedConstructorType(tpt, tree.args, classTp), tree.srcPos)
17271731
TypeTree(preciseTp)

tests/pos/applied_constructor_types.scala

+12-12
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,19 @@ object Test extends App {
3737
val box2: Box(O.InnerClass(n)) = Box(O.InnerClass(n))
3838
val box3: Box(O.InnerClass(O.m)) = Box(O.InnerClass(O.m))
3939

40-
val person: Person("Kasia", 27) = Person("Kasia", 27)
41-
val person1: Person("Kasia", n) = Person("Kasia", n)
42-
val person2: Person("Kasia", O.m) = Person("Kasia", O.m)
40+
val person: Person("Kasia", 27) = Person("Kasia", 27) // warn
41+
val person1: Person("Kasia", n) = Person("Kasia", n) // warn
42+
val person2: Person("Kasia", O.m) = Person("Kasia", O.m) // warn
4343

44-
val personPrime: PersonPrime("Kasia")(27) = PersonPrime("Kasia")(27)
45-
val personPrime1: PersonPrime("Kasia")(n) = PersonPrime("Kasia")(n)
46-
val personPrime2: PersonPrime("Kasia")(O.m) = PersonPrime("Kasia")(O.m)
44+
val personPrime: PersonPrime("Kasia")(27) = PersonPrime("Kasia")(27) // warn
45+
val personPrime1: PersonPrime("Kasia")(n) = PersonPrime("Kasia")(n) // warn
46+
val personPrime2: PersonPrime("Kasia")(O.m) = PersonPrime("Kasia")(O.m) // warn
4747

48-
val personBis: PersonBis("Kasia")(27) = PersonBis("Kasia")(27)
49-
val personBis1: PersonBis("Kasia")(n) = PersonBis("Kasia")(n)
50-
val personBis2: PersonBis("Kasia")(O.m) = PersonBis("Kasia")(O.m)
48+
val personBis: PersonBis("Kasia")(27) = PersonBis("Kasia")(27) // warn
49+
val personBis1: PersonBis("Kasia")(n) = PersonBis("Kasia")(n) // warn
50+
val personBis2: PersonBis("Kasia")(O.m) = PersonBis("Kasia")(O.m) // warn
5151

52-
val generic1: Generic(compiletime.erasedValue[Int]) = Generic(42)
53-
val generic2: Generic(??? : Int) = Generic(42)
54-
val generic3: Generic(43) = Generic(42)
52+
val generic1: Generic(compiletime.erasedValue[Int]) = Generic(42) // warn
53+
val generic2: Generic(??? : Int) = Generic(42) // warn
54+
val generic3: Generic(43) = Generic(42) // warn
5555
}
+2-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
-- [E208] Type Warning: tests/warn/applied_constructor_types.scala:6:10 ------------------------------------------------
1+
-- [E209] Type Warning: tests/warn/applied_constructor_types.scala:6:10 ------------------------------------------------
22
6 | val v1: UnspecificBox(4) = UnspecificBox(4) // warn
33
| ^^^^^^^^^^^^^^^^
4-
| Applied constructor type UnspecificBox(4) has no effect.
5-
| The resulting type of UnspecificBox(4) is the same as its base type, namely: UnspecificBox
6-
|
7-
| longer explanation available when compiling with `-explain`
4+
| Applied constructor type can only be used with classes that only have tracked parameters

0 commit comments

Comments
 (0)