Skip to content

Commit 2b71bfd

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

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
@@ -1331,25 +1331,6 @@ object Parsers {
13311331
*/
13321332
def qualId(): Tree = dotSelectors(termIdent())
13331333

1334-
/** Singleton ::= SimpleRef
1335-
* | SimpleLiteral
1336-
* | Singleton ‘.’ id
1337-
* | Singleton ‘(’ Singletons ‘)’
1338-
* -- not yet | Singleton ‘[’ Types ‘]’
1339-
*/
1340-
def singleton(): Tree =
1341-
val res =
1342-
if isSimpleLiteral then simpleLiteral()
1343-
else dotSelectors(simpleRef())
1344-
singletonArgs(res)
1345-
1346-
def singletonArgs(t: Tree): Tree =
1347-
if in.token == LPAREN && in.featureEnabled(Feature.modularity) then
1348-
singletonArgs(AppliedTypeTree(t, inParensWithCommas(commaSeparated(singleton))))
1349-
// else if in.token == LBRACKET && in.featureEnabled(Feature.modularity) then
1350-
// 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?
1351-
else t
1352-
13531334
/** SimpleLiteral ::= [‘-’] integerLiteral
13541335
* | [‘-’] floatingPointLiteral
13551336
* | booleanLiteral
@@ -2092,7 +2073,11 @@ object Parsers {
20922073
val start = in.skipToken()
20932074
typeBounds().withSpan(Span(start, in.lastOffset, start))
20942075
else
2095-
singletonArgs(simpleType1())
2076+
val tpt = simpleType1()
2077+
if in.featureEnabled(Feature.modularity) && in.token == LPAREN then
2078+
parArgumentExprss(wrapNew(tpt))
2079+
else
2080+
tpt
20962081

20972082
/** SimpleType1 ::= id
20982083
* | Singleton `.' id

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

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

1718+
def typedAppliedConstructorType(tree: untpd.Apply)(using Context) =
1719+
val Select(New(tpt), _) = tree.fun: @unchecked // Always wrapped in `New`, see `simpleType` in `Parsers`
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+
if preciseTp frozen_=:= classTp then
1726+
report.warning(em"Blop blop")
1727+
TypeTree(preciseTp)
1728+
17181729
/** Is given method reference applicable to argument trees `args`?
17191730
* @param resultType The expected result type of the application
17201731
*/

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

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

2559-
/** Type applied dependent class constructors in type positions */
2560-
private def typedTermAppliedTypeTree(tree: untpd.AppliedTypeTree, tpt1: Tree)(using Context): Tree = {
2561-
val AppliedTypeTree(originalTpt, args) = tree
2562-
if Feature.enabled(Feature.modularity) then
2563-
val constr =
2564-
if tpt1.tpe.typeSymbol.primaryConstructor.exists then
2565-
tpt1.tpe.typeSymbol.primaryConstructor
2566-
else
2567-
tpt1.tpe.typeSymbol.companionClass.primaryConstructor
2568-
// TODO(kπ) vvvvvvv Might want to take the first term list? or all term lists? depends on the rest of the logic.
2569-
// constr.paramSymss.flatten.foreach { p =>
2570-
// if p.isTerm && !p.flags.is(Tracked) then
2571-
// report.error(
2572-
// em"""The constructor parameter `${p.name}` of `${tpt1.tpe}` is not tracked.
2573-
// |Only tracked parameters are allowed in dependent constructor applications.""",
2574-
// tree.srcPos
2575-
// )
2576-
// }
2577-
def getArgs(t: Tree): List[List[Tree]] = t match
2578-
case AppliedTypeTree(base, args) => getArgs(base) :+ args
2579-
case _ => Nil
2580-
2581-
def instAll(t: Type, args: List[List[Tree]]): Type = (t.widenDealias, args) match
2582-
case (_, Nil) => t
2583-
case (t: MethodType, args :: rest) =>
2584-
val t1 = t.instantiate(args.map(_.tpe))
2585-
instAll(t1, rest)
2586-
case (_, args :: rest) =>
2587-
val t1 = t.appliedTo(args.map(_.tpe))
2588-
instAll(t1, rest)
2589-
2590-
constr.typeRef.underlying match
2591-
case mt: MethodOrPoly =>
2592-
val typedArgs = tree.args.map(a => (TypeTree(typedExpr(a).tpe)))
2593-
val preArgs = getArgs(tpt1)
2594-
TypeTree(instAll(mt, preArgs :+ typedArgs))
2595-
else
2596-
errorTree(tree, dependentMsg)
2597-
}
2598-
25992559
def typedAppliedTypeTree(tree: untpd.AppliedTypeTree)(using Context): Tree = {
26002560
val tpt1 = withoutMode(Mode.Pattern):
26012561
typed(tree.tpt, AnyTypeConstructorProto)
26022562

2603-
tree.args match
2604-
case arg :: _ if arg.isTerm =>
2605-
return typedTermAppliedTypeTree(tree, tpt1)
2606-
case _ =>
2607-
26082563
val tparams = tpt1.tpe.typeParams
26092564
if tpt1.tpe.isError then
26102565
val args1 = tree.args.mapconserve(typedType(_))
@@ -3556,7 +3511,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
35563511

35573512
/** Typecheck tree without adapting it, returning a typed tree.
35583513
* @param initTree the untyped tree
3559-
* @param pt the expected result type
3514+
* @param pt the expected result typ
35603515
* @param locked the set of type variables of the current typer state that cannot be interpolated
35613516
* at the present time
35623517
*/
@@ -3596,7 +3551,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
35963551

35973552
def typedUnnamed(tree: untpd.Tree): Tree = tree match {
35983553
case tree: untpd.Apply =>
3599-
if (ctx.mode is Mode.Pattern) typedUnApply(tree, pt) else typedApply(tree, pt)
3554+
if (ctx.mode is Mode.Pattern) typedUnApply(tree, pt)
3555+
else if (ctx.mode is Mode.Type) typedAppliedConstructorType(tree)
3556+
else typedApply(tree, pt)
36003557
case tree: untpd.This => typedThis(tree)
36013558
case tree: untpd.Number => typedNumber(tree, pt)
36023559
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)