Skip to content

Commit 496830e

Browse files
committed
Allow multiple context bounds in {...}
1 parent 59a4b7d commit 496830e

File tree

10 files changed

+66
-15
lines changed

10 files changed

+66
-15
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,8 @@ object desugar {
11441144
case tree: TypeDef => tree.name.toString
11451145
case tree: AppliedTypeTree if followArgs && tree.args.nonEmpty =>
11461146
s"${apply(x, tree.tpt)}_${extractArgs(tree.args)}"
1147+
case ContextBoundTypeTree(tycon, paramName, _) =>
1148+
s"${apply(x, tycon)}_$paramName"
11471149
case InfixOp(left, op, right) =>
11481150
if followArgs then s"${op.name}_${extractArgs(List(left, right))}"
11491151
else op.name.toString

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
118118
case class ContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree])(implicit @constructorOnly src: SourceFile) extends TypTree
119119
case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree)(implicit @constructorOnly src: SourceFile) extends DefTree
120120
case class ExtMethods(paramss: List[ParamClause], methods: List[Tree])(implicit @constructorOnly src: SourceFile) extends Tree
121+
case class ContextBoundTypeTree(tycon: Tree, paramName: TypeName, ownName: TermName)(implicit @constructorOnly src: SourceFile) extends Tree
121122
case class MacroTree(expr: Tree)(implicit @constructorOnly src: SourceFile) extends Tree
122123

123124
case class ImportSelector(imported: Ident, renamed: Tree = EmptyTree, bound: Tree = EmptyTree)(implicit @constructorOnly src: SourceFile) extends Tree {
@@ -677,6 +678,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
677678
def ExtMethods(tree: Tree)(paramss: List[ParamClause], methods: List[Tree])(using Context): Tree = tree match
678679
case tree: ExtMethods if (paramss eq tree.paramss) && (methods == tree.methods) => tree
679680
case _ => finalize(tree, untpd.ExtMethods(paramss, methods)(tree.source))
681+
def ContextBoundTypeTree(tree: Tree)(tycon: Tree, paramName: TypeName, ownName: TermName)(using Context): Tree = tree match
682+
case tree: ContextBoundTypeTree if (tycon eq tree.tycon) && paramName == tree.paramName && ownName == tree.ownName => tree
683+
case _ => finalize(tree, untpd.ContextBoundTypeTree(tycon, paramName, ownName)(tree.source))
680684
def ImportSelector(tree: Tree)(imported: Ident, renamed: Tree, bound: Tree)(using Context): Tree = tree match {
681685
case tree: ImportSelector if (imported eq tree.imported) && (renamed eq tree.renamed) && (bound eq tree.bound) => tree
682686
case _ => finalize(tree, untpd.ImportSelector(imported, renamed, bound)(tree.source))
@@ -742,6 +746,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
742746
cpy.PatDef(tree)(mods, transform(pats), transform(tpt), transform(rhs))
743747
case ExtMethods(paramss, methods) =>
744748
cpy.ExtMethods(tree)(transformParamss(paramss), transformSub(methods))
749+
case ContextBoundTypeTree(tycon, paramName, ownName) =>
750+
cpy.ContextBoundTypeTree(tree)(transform(tycon), paramName, ownName)
745751
case ImportSelector(imported, renamed, bound) =>
746752
cpy.ImportSelector(tree)(transformSub(imported), transform(renamed), transform(bound))
747753
case Number(_, _) | TypedSplice(_) =>
@@ -797,6 +803,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
797803
this(this(this(x, pats), tpt), rhs)
798804
case ExtMethods(paramss, methods) =>
799805
this(paramss.foldLeft(x)(apply), methods)
806+
case ContextBoundTypeTree(tycon, paramName, ownName) =>
807+
this(x, tycon)
800808
case ImportSelector(imported, renamed, bound) =>
801809
this(this(this(x, imported), renamed), bound)
802810
case Number(_, _) =>

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2168,11 +2168,16 @@ object Parsers {
21682168
else atSpan((t.span union cbs.head.span).start) { ContextBounds(t, cbs) }
21692169
}
21702170

2171+
/** ContextBound ::= Type [`as` id] */
2172+
def contextBound(pname: TypeName): Tree =
2173+
ContextBoundTypeTree(toplevelTyp(), pname, EmptyTermName)
2174+
21712175
def contextBounds(pname: TypeName): List[Tree] =
21722176
if in.isColon then
2173-
atSpan(in.skipToken()) {
2174-
AppliedTypeTree(toplevelTyp(), Ident(pname))
2175-
} :: contextBounds(pname)
2177+
in.nextToken()
2178+
if in.token == LBRACE && in.featureEnabled(Feature.modularity)
2179+
then inBraces(commaSeparated(() => contextBound(pname)))
2180+
else contextBound(pname) :: contextBounds(pname)
21762181
else if in.token == VIEWBOUND then
21772182
report.errorOrMigrationWarning(
21782183
em"view bounds `<%' are no longer supported, use a context bound `:' instead",

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
373373
changePrec(GlobalPrec) { keywordStr("for ") ~ Text(enums map enumText, "; ") ~ sep ~ toText(expr) }
374374

375375
def cxBoundToText(bound: untpd.Tree): Text = bound match { // DD
376-
case AppliedTypeTree(tpt, _) => " : " ~ toText(tpt)
376+
case ContextBoundTypeTree(tpt, _, _) => " : " ~ toText(tpt)
377377
case untpd.Function(_, tpt) => " <% " ~ toText(tpt)
378378
}
379379

@@ -640,7 +640,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
640640
def toTextAnnot =
641641
toTextLocal(arg) ~~ annotText(annot.symbol.enclosingClass, annot)
642642
def toTextRetainsAnnot =
643-
try changePrec(GlobalPrec)(toText(arg) ~ "^" ~ toTextCaptureSet(captureSet))
643+
try changePrec(GlobalPrec)(toTextLocal(arg) ~ "^" ~ toTextCaptureSet(captureSet))
644644
catch case ex: IllegalCaptureRef => toTextAnnot
645645
if annot.symbol.maybeOwner.isRetains
646646
&& Feature.ccEnabled && !printDebug
@@ -729,9 +729,18 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
729729
case GenAlias(pat, expr) =>
730730
toText(pat) ~ " = " ~ toText(expr)
731731
case ContextBounds(bounds, cxBounds) =>
732-
cxBounds.foldLeft(toText(bounds)) {(t, cxb) =>
733-
t ~ cxBoundToText(cxb)
734-
}
732+
if Feature.enabled(Feature.modularity) then
733+
def boundsText(bounds: Tree) = bounds match
734+
case ContextBoundTypeTree(tpt, _, ownName) =>
735+
toText(tpt) ~ (" as " ~ toText(ownName) `provided` !ownName.isEmpty)
736+
case bounds => toText(bounds)
737+
cxBounds match
738+
case bound :: Nil => ": " ~ boundsText(bound)
739+
case _ => ": {" ~ Text(cxBounds.map(boundsText), ", ") ~ "}"
740+
else
741+
cxBounds.foldLeft(toText(bounds)) {(t, cxb) =>
742+
t ~ cxBoundToText(cxb)
743+
}
735744
case PatDef(mods, pats, tpt, rhs) =>
736745
modText(mods, NoSymbol, keywordStr("val"), isType = false) ~~
737746
toText(pats, ", ") ~ optAscription(tpt) ~ optText(rhs)(" = " ~ _)
@@ -776,6 +785,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
776785
prefix ~~ idx.toString ~~ "|" ~~ tpeText ~~ "|" ~~ argsText ~~ "|" ~~ contentText ~~ postfix
777786
case CapturesAndResult(refs, parent) =>
778787
changePrec(GlobalPrec)("^{" ~ Text(refs.map(toText), ", ") ~ "}" ~ toText(parent))
788+
case ContextBoundTypeTree(tycon, pname, ownName) =>
789+
toText(pname) ~ " : " ~ toText(tycon) ~ (" as " ~ toText(ownName) `provided` !ownName.isEmpty)
779790
case _ =>
780791
tree.fallbackToText(this)
781792
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2204,6 +2204,16 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
22042204
tree.tpFun(tsyms, vsyms)
22052205
completeTypeTree(InferredTypeTree(), tp, tree)
22062206

2207+
def typedContextBoundTypeTree(tree: untpd.ContextBoundTypeTree)(using Context): Tree =
2208+
val tycon = typedType(tree.tycon)
2209+
val tyconSplice = untpd.TypedSplice(tycon)
2210+
val tparam = untpd.Ident(tree.paramName).withSpan(tree.span)
2211+
if tycon.tpe.typeParams.nonEmpty then
2212+
typed(untpd.AppliedTypeTree(tyconSplice, tparam :: Nil))
2213+
else
2214+
errorTree(tree,
2215+
em"""Illegal context bound: ${tycon.tpe} does not take type parameters.""")
2216+
22072217
def typedSingletonTypeTree(tree: untpd.SingletonTypeTree)(using Context): SingletonTypeTree = {
22082218
val ref1 = typedExpr(tree.ref, SingletonTypeProto)
22092219
checkStable(ref1.tpe, tree.srcPos, "singleton type")
@@ -3194,6 +3204,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
31943204
case tree: untpd.UnApply => typedUnApply(tree, pt)
31953205
case tree: untpd.Tuple => typedTuple(tree, pt)
31963206
case tree: untpd.InLambdaTypeTree => typedInLambdaTypeTree(tree, pt)
3207+
case tree: untpd.ContextBoundTypeTree => typedContextBoundTypeTree(tree)
31973208
case tree: untpd.InfixOp => typedInfixOp(tree, pt)
31983209
case tree: untpd.ParsedTry => typedTry(tree, pt)
31993210
case tree @ untpd.PostfixOp(qual, Ident(nme.WILDCARD)) => typedAsFunction(tree, pt)

tests/neg/i9330.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
val x = {
2-
() == "" // error
2+
() == ""
33
implicit def foo[A: A] // error // error // error
44
}

tests/pos/FromString-typeparam.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//> using options -language:experimental.modularity -source future
2+
3+
trait FromString[A]:
4+
def fromString(s: String): A
5+
6+
given FromString[Int] = _.toInt
7+
8+
given FromString[Double] = _.toDouble
9+
10+
def add[N: {FromString, Numeric}](a: String, b: String): N =
11+
val num = summon[Numeric[N]]
12+
val N = summon[FromString[N]]
13+
num.plus(N.fromString(a), N.fromString(b))

tests/semanticdb/expect/Methods.expect.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class Methods/*<-example::Methods#*/[T/*<-example::Methods#[T]*/] {
1515
def m6/*<-example::Methods#m6().*/(x/*<-example::Methods#m6().(x)*/: Int/*->scala::Int#*/) = ???/*->scala::Predef.`???`().*/
1616
def m6/*<-example::Methods#m6(+1).*/(x/*<-example::Methods#m6(+1).(x)*/: List/*->example::Methods#List#*/[T/*->example::Methods#[T]*/]) = ???/*->scala::Predef.`???`().*/
1717
def m6/*<-example::Methods#m6(+2).*/(x/*<-example::Methods#m6(+2).(x)*/: scala.List/*->scala::package.List#*/[T/*->example::Methods#[T]*/]) = ???/*->scala::Predef.`???`().*/
18-
def m7/*<-example::Methods#m7().*/[U/*<-example::Methods#m7().[U]*//*<-example::Methods#m7().(evidence$1)*/: Ordering/*->scala::math::Ordering#*/](c/*<-example::Methods#m7().(c)*/: Methods/*->example::Methods#*/[T/*->example::Methods#[T]*/], l/*<-example::Methods#m7().(l)*/: List/*->example::Methods#List#*/[U/*->example::Methods#m7().[U]*/]) = ???/*->scala::Predef.`???`().*/
18+
def m7/*<-example::Methods#m7().*/[U/*<-example::Methods#m7().[U]*/: Ordering/*->example::Methods#m7().[U]*//*<-example::Methods#m7().(evidence$1)*/](c/*<-example::Methods#m7().(c)*/: Methods/*->example::Methods#*/[T/*->example::Methods#[T]*/], l/*<-example::Methods#m7().(l)*/: List/*->example::Methods#List#*/[U/*->example::Methods#m7().[U]*/]) = ???/*->scala::Predef.`???`().*/
1919
def `m8()./*<-example::Methods#`m8().`().*/`() = ???/*->scala::Predef.`???`().*/
2020
class `m9()./*<-example::Methods#`m9().`#*/`
2121
def m9/*<-example::Methods#m9().*/(x/*<-example::Methods#m9().(x)*/: `m9().`/*->example::Methods#`m9().`#*/) = ???/*->scala::Predef.`???`().*/

tests/semanticdb/expect/Synthetic.expect.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class Synthetic/*<-example::Synthetic#*/ {
3030
null.asInstanceOf/*->scala::Any#asInstanceOf().*/[Int/*->scala::Int#*/ => Int/*->scala::Int#*/](2)
3131
}
3232

33-
class J/*<-example::Synthetic#J#*/[T/*<-example::Synthetic#J#[T]*//*<-example::Synthetic#J#evidence$1.*/: Manifest/*->scala::Predef.Manifest#*/] { val arr/*<-example::Synthetic#J#arr.*/ = Array/*->scala::Array.*/.empty/*->scala::Array.empty().*/[T/*->example::Synthetic#J#[T]*/] }
33+
class J/*<-example::Synthetic#J#*/[T/*<-example::Synthetic#J#[T]*/: /*<-example::Synthetic#J#evidence$1.*/Manifest/*->scala::Predef.Manifest#*//*->example::Synthetic#J#[T]*/] { val arr/*<-example::Synthetic#J#arr.*/ = Array/*->scala::Array.*/.empty/*->scala::Array.empty().*/[T/*->example::Synthetic#J#[T]*/] }
3434

3535
class F/*<-example::Synthetic#F#*/
3636
implicit val ordering/*<-example::Synthetic#ordering.*/: Ordering/*->scala::package.Ordering#*/[F/*->example::Synthetic#F#*/] = ???/*->scala::Predef.`???`().*/

tests/semanticdb/metac.expect

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2732,8 +2732,8 @@ Occurrences:
27322732
[16:29..16:32): ??? -> scala/Predef.`???`().
27332733
[17:6..17:8): m7 <- example/Methods#m7().
27342734
[17:9..17:10): U <- example/Methods#m7().[U]
2735-
[17:10..17:10): <- example/Methods#m7().(evidence$1)
2736-
[17:12..17:20): Ordering -> scala/math/Ordering#
2735+
[17:12..17:20): Ordering -> example/Methods#m7().[U]
2736+
[17:12..17:12): <- example/Methods#m7().(evidence$1)
27372737
[17:22..17:23): c <- example/Methods#m7().(c)
27382738
[17:25..17:32): Methods -> example/Methods#
27392739
[17:33..17:34): T -> example/Methods#[T]
@@ -3533,7 +3533,7 @@ Uri => Synthetic.scala
35333533
Text => empty
35343534
Language => Scala
35353535
Symbols => 52 entries
3536-
Occurrences => 136 entries
3536+
Occurrences => 137 entries
35373537
Synthetics => 39 entries
35383538

35393539
Symbols:
@@ -3659,8 +3659,9 @@ Occurrences:
36593659
[32:8..32:9): J <- example/Synthetic#J#
36603660
[32:9..32:9): <- example/Synthetic#J#`<init>`().
36613661
[32:10..32:11): T <- example/Synthetic#J#[T]
3662-
[32:11..32:11): <- example/Synthetic#J#evidence$1.
3662+
[32:13..32:13): <- example/Synthetic#J#evidence$1.
36633663
[32:13..32:21): Manifest -> scala/Predef.Manifest#
3664+
[32:13..32:21): Manifest -> example/Synthetic#J#[T]
36643665
[32:29..32:32): arr <- example/Synthetic#J#arr.
36653666
[32:35..32:40): Array -> scala/Array.
36663667
[32:41..32:46): empty -> scala/Array.empty().

0 commit comments

Comments
 (0)