Skip to content

Commit ab7d45a

Browse files
mbovelKacperFKorban
andcommitted
Parse applied constructor type arguments as trees
Co-authored-by: Kacper Korban <[email protected]>
1 parent 4848e07 commit ab7d45a

9 files changed

+93
-86
lines changed

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

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,25 +1320,6 @@ object Parsers {
13201320
*/
13211321
def qualId(): Tree = dotSelectors(termIdent())
13221322

1323-
/** Singleton ::= SimpleRef
1324-
* | SimpleLiteral
1325-
* | Singleton ‘.’ id
1326-
* | Singleton ‘(’ Singletons ‘)’
1327-
* -- not yet | Singleton ‘[’ Types ‘]’
1328-
*/
1329-
def singleton(): Tree =
1330-
val res =
1331-
if isSimpleLiteral then simpleLiteral()
1332-
else dotSelectors(simpleRef())
1333-
singletonArgs(res)
1334-
1335-
def singletonArgs(t: Tree): Tree =
1336-
if in.token == LPAREN && in.featureEnabled(Feature.modularity) then
1337-
singletonArgs(AppliedTypeTree(t, inParensWithCommas(commaSeparated(singleton))))
1338-
// else if in.token == LBRACKET && in.featureEnabled(Feature.modularity) then
1339-
// singletonArgs(AppliedTypeTree(t, inBrackets(commaSeparated(() => typ())))) // should this be marked in a different way, so that we know that it is a type application, and not a term application?
1340-
else t
1341-
13421323
/** SimpleLiteral ::= [‘-’] integerLiteral
13431324
* | [‘-’] floatingPointLiteral
13441325
* | booleanLiteral
@@ -2059,7 +2040,11 @@ object Parsers {
20592040
val start = in.skipToken()
20602041
typeBounds().withSpan(Span(start, in.lastOffset, start))
20612042
else
2062-
singletonArgs(simpleType1())
2043+
val tpt = simpleType1()
2044+
if in.featureEnabled(Feature.modularity) && in.token == LPAREN then
2045+
parArgumentExprss(wrapNew(tpt))
2046+
else
2047+
tpt
20632048

20642049
/** SimpleType1 ::= id
20652050
* | Singleton `.' id

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,6 +1694,17 @@ trait Applications extends Compatibility {
16941694
def typedUnApply(tree: untpd.UnApply, selType: Type)(using Context): UnApply =
16951695
throw new UnsupportedOperationException("cannot type check an UnApply node")
16961696

1697+
def typedAppliedConstructorType(tree: untpd.Apply)(using Context) =
1698+
val Select(New(tpt), _) = tree.fun: @unchecked // Always wrapped in `New`, see `simpleType` in `Parsers`
1699+
val tree1 = typedExpr(tree)
1700+
val widenSkolemsMap = new TypeMap:
1701+
def apply(tp: Type) = mapOver(tp.widenSkolem)
1702+
val preciseTp = widenSkolemsMap(tree1.tpe)
1703+
val classTp = typedType(tpt).tpe
1704+
if preciseTp frozen_=:= classTp then
1705+
report.warning(em"Blop blop")
1706+
TypeTree(preciseTp)
1707+
16971708
/** Is given method reference applicable to argument trees `args`?
16981709
* @param resultType The expected result type of the application
16991710
*/

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

Lines changed: 4 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2514,55 +2514,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
25142514
assignType(cpy.RefinedTypeTree(tree)(tpt1, refinements1), tpt1, refinements1, refineCls)
25152515
}
25162516

2517-
/** Type applied dependent class constructors in type positions */
2518-
private def typedTermAppliedTypeTree(tree: untpd.AppliedTypeTree, tpt1: Tree)(using Context): Tree = {
2519-
val AppliedTypeTree(originalTpt, args) = tree
2520-
if Feature.enabled(Feature.modularity) then
2521-
val constr =
2522-
if tpt1.tpe.typeSymbol.primaryConstructor.exists then
2523-
tpt1.tpe.typeSymbol.primaryConstructor
2524-
else
2525-
tpt1.tpe.typeSymbol.companionClass.primaryConstructor
2526-
// TODO(kπ) vvvvvvv Might want to take the first term list? or all term lists? depends on the rest of the logic.
2527-
// constr.paramSymss.flatten.foreach { p =>
2528-
// if p.isTerm && !p.flags.is(Tracked) then
2529-
// report.error(
2530-
// em"""The constructor parameter `${p.name}` of `${tpt1.tpe}` is not tracked.
2531-
// |Only tracked parameters are allowed in dependent constructor applications.""",
2532-
// tree.srcPos
2533-
// )
2534-
// }
2535-
def getArgs(t: Tree): List[List[Tree]] = t match
2536-
case AppliedTypeTree(base, args) => getArgs(base) :+ args
2537-
case _ => Nil
2538-
2539-
def instAll(t: Type, args: List[List[Tree]]): Type = (t.widenDealias, args) match
2540-
case (_, Nil) => t
2541-
case (t: MethodType, args :: rest) =>
2542-
val t1 = t.instantiate(args.map(_.tpe))
2543-
instAll(t1, rest)
2544-
case (_, args :: rest) =>
2545-
val t1 = t.appliedTo(args.map(_.tpe))
2546-
instAll(t1, rest)
2547-
2548-
constr.typeRef.underlying match
2549-
case mt: MethodOrPoly =>
2550-
val typedArgs = tree.args.map(a => (TypeTree(typedExpr(a).tpe)))
2551-
val preArgs = getArgs(tpt1)
2552-
TypeTree(instAll(mt, preArgs :+ typedArgs))
2553-
else
2554-
errorTree(tree, dependentMsg)
2555-
}
2556-
25572517
def typedAppliedTypeTree(tree: untpd.AppliedTypeTree)(using Context): Tree = {
25582518
val tpt1 = withoutMode(Mode.Pattern):
25592519
typed(tree.tpt, AnyTypeConstructorProto)
25602520

2561-
tree.args match
2562-
case arg :: _ if arg.isTerm =>
2563-
return typedTermAppliedTypeTree(tree, tpt1)
2564-
case _ =>
2565-
25662521
val tparams = tpt1.tpe.typeParams
25672522
if tpt1.tpe.isError then
25682523
val args1 = tree.args.mapconserve(typedType(_))
@@ -3522,7 +3477,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
35223477

35233478
/** Typecheck tree without adapting it, returning a typed tree.
35243479
* @param initTree the untyped tree
3525-
* @param pt the expected result type
3480+
* @param pt the expected result typ
35263481
* @param locked the set of type variables of the current typer state that cannot be interpolated
35273482
* at the present time
35283483
*/
@@ -3562,7 +3517,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
35623517

35633518
def typedUnnamed(tree: untpd.Tree): Tree = tree match {
35643519
case tree: untpd.Apply =>
3565-
if (ctx.mode is Mode.Pattern) typedUnApply(tree, pt) else typedApply(tree, pt)
3520+
if (ctx.mode is Mode.Pattern) typedUnApply(tree, pt)
3521+
else if (ctx.mode is Mode.Type) typedAppliedConstructorType(tree)
3522+
else typedApply(tree, pt)
35663523
case tree: untpd.This => typedThis(tree)
35673524
case tree: untpd.Number => typedNumber(tree, pt)
35683525
case tree: untpd.Literal => typedLiteral(tree)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
-- [E006] Not Found Error: tests/neg/applied_constructors.scala:8:10 ---------------------------------------------------
2+
8 | val v1: f(1) = f(1) // error
3+
| ^
4+
| Not found: type f
5+
|
6+
| longer explanation available when compiling with `-explain`
7+
Blop blop
8+
-- [E006] Not Found Error: tests/neg/applied_constructors.scala:9:10 ---------------------------------------------------
9+
9 | val v2: id(1) = f(1) // error
10+
| ^^
11+
| Not found: type id - did you mean is?
12+
|
13+
| longer explanation available when compiling with `-explain`
14+
Blop blop
15+
-- [E006] Not Found Error: tests/neg/applied_constructors.scala:10:10 --------------------------------------------------
16+
10 | val v3: idDependent(1) = f(1) // error
17+
| ^^^^^^^^^^^
18+
| Not found: type idDependent
19+
|
20+
| longer explanation available when compiling with `-explain`
21+
Blop blop
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import scala.language.experimental.modularity
2+
3+
def f(x: Int): Int = x
4+
def id[T](x: T): T = x
5+
def idDependent(x: Any): x.type = x
6+
7+
def test =
8+
val v1: f(1) = f(1) // error
9+
val v2: id(1) = f(1) // error
10+
val v3: idDependent(1) = f(1) // error
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import scala.language.experimental.modularity
2+
3+
class Box(tracked val v: Any)
4+
class C(tracked val x: Int)
5+
class NC(tracked val c: C)
6+
class NNC(tracked val c: NC)
7+
class F[A](tracked val a: Int)
8+
class G[A](tracked val a: A)
9+
class NF[A](tracked val f: F[A])
10+
11+
object O:
12+
val m: Int = 42
13+
14+
class InnerClass(tracked val x: Int)
15+
16+
object Test extends App {
17+
val c: C(42) = C(42)
18+
val nc: NC(C(42)) = NC(C(42))
19+
val nc1: NC(c) = NC(c)
20+
val nnc: NNC(NC(C(42))) = NNC(NC(C(42)))
21+
val f: F[Int](42) = F[Int](42)
22+
val f2: F[Int](42) = F(42)
23+
val f3: F(42) = F(42)
24+
val g: G(42) = G(42)
25+
26+
val n: Int = 42
27+
val c2: C(n) = C(n)
28+
val c3: C(O.m) = C(O.m)
29+
30+
val box: Box(O.InnerClass(42)) = Box(O.InnerClass(42))
31+
val box2: Box(O.InnerClass(n)) = Box(O.InnerClass(n))
32+
val box3: Box(O.InnerClass(O.m)) = Box(O.InnerClass(O.m))
33+
val box4: Box(n) = Box(O.InnerClass(n).x)
34+
val box5: Box(O.m) = Box(O.InnerClass(O.m).x)
35+
}

tests/pos/applied_constructors.scala

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TODO
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import scala.language.experimental.modularity
2+
3+
class UnspecificBox(val v: Any)
4+
5+
def test =
6+
val v1: UnspecificBox(4) = UnspecificBox(4) // warn

0 commit comments

Comments
 (0)