Skip to content

Commit 8515ad0

Browse files
committed
Review changes for applied constructor types
1 parent b964de9 commit 8515ad0

File tree

8 files changed

+48
-28
lines changed

8 files changed

+48
-28
lines changed

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

+1-3
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,12 @@ object NamerOps:
3939
*/
4040
extension (tp: Type)
4141
def separateRefinements(cls: ClassSymbol, refinements: mutable.LinkedHashMap[Name, Type] | Null)(using Context): Type =
42-
val widenSkolemsMap = new TypeMap:
43-
def apply(tp: Type) = mapOver(tp.widenSkolem)
4442
tp match
4543
case RefinedType(tp1, rname, rinfo) =>
4644
try tp1.separateRefinements(cls, refinements)
4745
finally
4846
if refinements != null then
49-
val rinfo1 = widenSkolemsMap(rinfo)
47+
val rinfo1 = rinfo.widenSkolems
5048
refinements(rname) = refinements.get(rname) match
5149
case Some(tp) => tp & rinfo1
5250
case None => rinfo1

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

+6-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ class TypeUtils:
5353
case ps => ps.reduceLeft(AndType(_, _))
5454
}
5555

56+
def widenSkolems(using Context): Type =
57+
val widenSkolemsMap = new TypeMap:
58+
def apply(tp: Type) = mapOver(tp.widenSkolem)
59+
widenSkolemsMap(self)
60+
5661
/** The element types of this tuple type, which can be made up of EmptyTuple, TupleX and `*:` pairs
5762
*/
5863
def tupleElementTypes(using Context): Option[List[Type]] =
@@ -134,7 +139,7 @@ class TypeUtils:
134139
case t => throw TypeError(em"Malformed NamedTuple: names must be string types, but $t was found.")
135140
val values = vals.tupleElementTypesUpTo(bound, normalize).getOrElse(Nil)
136141
names.zip(values)
137-
142+
138143
(if normalize then self.normalized else self).dealias match
139144
// for desugaring and printer, ignore derived types to avoid infinite recursion in NamedTuple.unapply
140145
case defn.NamedTupleDirect(nmes, vals) => extractNamesTypes(nmes, vals)

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -2040,7 +2040,7 @@ object Parsers {
20402040
/** SimpleType ::= SimpleLiteral
20412041
* | ‘?’ TypeBounds
20422042
* | SimpleType1
2043-
* | SimpleType ‘(’ Singletons ‘)’ -- under language.experimental.modularity, checked in Typer
2043+
* | SimpleType ‘(’ Singletons ‘)’
20442044
* Singletons ::= Singleton {‘,’ Singleton}
20452045
*/
20462046
def simpleType(): Tree =

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -3475,6 +3475,6 @@ final class PointlessAppliedConstructorType(tpt: untpd.Tree, args: List[untpd.Tr
34753475
final class OnlyFullyDependentAppliedConstructorType()(using Context)
34763476
extends TypeMsg(OnlyFullyDependentAppliedConstructorTypeID):
34773477
override protected def msg(using Context): String =
3478-
i"Applied constructor type can only be used with classes that only have tracked parameters"
3478+
i"Applied constructor type can only be used with classes where all parameters in the first parameter list are tracked"
34793479

34803480
override protected def explain(using Context): String = ""

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

+25-16
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,10 @@ trait Applications extends Compatibility {
12821282
}
12831283
else {
12841284
val app = tree.fun match
1285+
case _ if ctx.mode.is(Mode.Type) && Feature.enabled(Feature.modularity) && !ctx.isAfterTyper =>
1286+
untpd.methPart(tree.fun) match
1287+
case Select(nw @ New(_), _) => typedAppliedConstructorType(nw, tree.args, tree)
1288+
case _ => realApply
12851289
case untpd.TypeApply(_: untpd.SplicePattern, _) if Feature.quotedPatternsWithPolymorphicFunctionsEnabled =>
12861290
typedAppliedSpliceWithTypes(tree, pt)
12871291
case _: untpd.SplicePattern => typedAppliedSplice(tree, pt)
@@ -1715,22 +1719,27 @@ trait Applications extends Compatibility {
17151719
def typedUnApply(tree: untpd.UnApply, selType: Type)(using Context): UnApply =
17161720
throw new UnsupportedOperationException("cannot type check an UnApply node")
17171721

1718-
def typedAppliedConstructorType(tree: untpd.Apply)(using Context) = untpd.methPart(tree) match
1719-
case Select(New(tpt), _) =>
1720-
val tree1 = typedExpr(tree)
1721-
val widenSkolemsMap = new TypeMap:
1722-
def apply(tp: Type) = mapOver(tp.widenSkolem)
1723-
val preciseTp = widenSkolemsMap(tree1.tpe)
1724-
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)
1729-
if !preciseTp.isError && (preciseTp frozen_=:= classTp) then
1730-
report.warning(PointlessAppliedConstructorType(tpt, tree.args, classTp), tree.srcPos)
1731-
TypeTree(preciseTp)
1732-
case _ =>
1733-
throw TypeError(em"Unexpected applied constructor type: $tree")
1722+
/** Typecheck an applied constructor type – An Apply node in Type mode.
1723+
* This expands to the type this term would have if it were typed as an expression.
1724+
*
1725+
* e.g.
1726+
* ```scala
1727+
* // class C(tracked val v: Any)
1728+
* val c: C(42) = ???
1729+
* ```
1730+
*/
1731+
def typedAppliedConstructorType(nw: untpd.New, args: List[untpd.Tree], tree: untpd.Apply)(using Context) =
1732+
val tree1 = typedExpr(tree)
1733+
val preciseTp = tree1.tpe.widenSkolems
1734+
val classTp = typedType(nw.tpt).tpe
1735+
def classSymbolHasOnlyTrackedParameters =
1736+
!classTp.classSymbol.primaryConstructor.paramSymss.nestedExists: param =>
1737+
param.isTerm && !param.is(Tracked)
1738+
if !preciseTp.isError && !classSymbolHasOnlyTrackedParameters then
1739+
report.warning(OnlyFullyDependentAppliedConstructorType(), tree.srcPos)
1740+
if !preciseTp.isError && (preciseTp frozen_=:= classTp) then
1741+
report.warning(PointlessAppliedConstructorType(nw.tpt, args, classTp), tree.srcPos)
1742+
TypeTree(preciseTp)
17341743

17351744
/** Is given method reference applicable to argument trees `args`?
17361745
* @param resultType The expected result type of the application

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

+2-4
Original file line numberDiff line numberDiff line change
@@ -3511,7 +3511,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
35113511

35123512
/** Typecheck tree without adapting it, returning a typed tree.
35133513
* @param initTree the untyped tree
3514-
* @param pt the expected result typ
3514+
* @param pt the expected result type
35153515
* @param locked the set of type variables of the current typer state that cannot be interpolated
35163516
* at the present time
35173517
*/
@@ -3551,9 +3551,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
35513551

35523552
def typedUnnamed(tree: untpd.Tree): Tree = tree match {
35533553
case tree: untpd.Apply =>
3554-
if (ctx.mode is Mode.Pattern) typedUnApply(tree, pt)
3555-
else if (Feature.enabled(modularity) && ctx.mode.is(Mode.Type) && !ctx.isAfterTyper) typedAppliedConstructorType(tree)
3556-
else typedApply(tree, pt)
3554+
if (ctx.mode is Mode.Pattern) typedUnApply(tree, pt) else typedApply(tree, pt)
35573555
case tree: untpd.This => typedThis(tree)
35583556
case tree: untpd.Number => typedNumber(tree, pt)
35593557
case tree: untpd.Literal => typedLiteral(tree)

docs/_docs/reference/experimental/modularity.md

+10
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,16 @@ SimpleType ::= SimpleLiteral
224224

225225
A `SimpleType` can now optionally be followed by `ParArgumentExprs`.
226226

227+
The arguments are used to typecheck the whole type, as if it was a normal
228+
constructor application. For classes with `tracked` parameters this will mean
229+
that the resulting type will have a refinement for each `tracked` parameter.
230+
231+
For example, given the following class definition:
232+
```scala
233+
class Person(tracked val name: String, tracked val age: Int)
234+
```
235+
**Type** `Person("Kasia", 27)` will be translated to `Person { val name: "Kasia"; val age: 27 }`.
236+
227237
## Allow Class Parents to be Refined Types
228238

229239
Since `tracked` parameters create refinements in constructor types,
+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- [E209] Type Warning: tests/warn/applied_constructor_types.scala:6:10 ------------------------------------------------
1+
-- [E211] Type Warning: tests/warn/applied_constructor_types.scala:6:10 ------------------------------------------------
22
6 | val v1: UnspecificBox(4) = UnspecificBox(4) // warn
33
| ^^^^^^^^^^^^^^^^
4-
| Applied constructor type can only be used with classes that only have tracked parameters
4+
|Applied constructor type can only be used with classes where all parameters in the first parameter list are tracked

0 commit comments

Comments
 (0)