Skip to content

Commit abb40d7

Browse files
committed
Represent untyped operators as Ident instead of Name
This has two advantages: - We can distinguish BackquotedIdent from Ident, allowing the user to use a defined "type `&`", see testcase. - We get better positions for the operators. This is useful in IDEs, for example to get the type at point.
1 parent da7d723 commit abb40d7

File tree

9 files changed

+44
-39
lines changed

9 files changed

+44
-39
lines changed

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -739,23 +739,23 @@ object desugar {
739739

740740
/** Translate infix operation expression left op right
741741
*/
742-
def makeBinop(left: Tree, op: Name, right: Tree): Tree = {
742+
def makeBinop(left: Tree, op: Ident, right: Tree): Tree = {
743743
def assignToNamedArg(arg: Tree) = arg match {
744744
case Assign(Ident(name), rhs) => cpy.NamedArg(arg)(name, rhs)
745745
case _ => arg
746746
}
747-
if (isLeftAssoc(op)) {
747+
if (isLeftAssoc(op.name)) {
748748
val args: List[Tree] = right match {
749749
case Parens(arg) => assignToNamedArg(arg) :: Nil
750750
case Tuple(args) => args mapConserve assignToNamedArg
751751
case _ => right :: Nil
752752
}
753-
Apply(Select(left, op), args)
753+
Apply(Select(left, op.name), args)
754754
} else {
755755
val x = ctx.freshName().toTermName
756756
new InfixOpBlock(
757757
ValDef(x, TypeTree(), left).withMods(synthetic),
758-
Apply(Select(right, op), Ident(x)))
758+
Apply(Select(right, op.name), Ident(x)))
759759
}
760760
}
761761

@@ -956,25 +956,25 @@ object desugar {
956956
Apply(Select(Apply(Ident(nme.StringContext), strs), id), elems)
957957
case InfixOp(l, op, r) =>
958958
if (ctx.mode is Mode.Type)
959-
if (op == tpnme.raw.AMP) AndTypeTree(l, r) // l & r
960-
else if (op == tpnme.raw.BAR) OrTypeTree(l, r) // l | r
961-
else AppliedTypeTree(Ident(op), l :: r :: Nil) // op[l, r]
959+
if (!op.isBackquoted && op.name == tpnme.raw.AMP) AndTypeTree(l, r) // l & r
960+
else if (!op.isBackquoted && op.name == tpnme.raw.BAR) OrTypeTree(l, r) // l | r
961+
else AppliedTypeTree(op, l :: r :: Nil) // op[l, r]
962962
else if (ctx.mode is Mode.Pattern)
963-
Apply(Ident(op), l :: r :: Nil) // op(l, r)
963+
Apply(op, l :: r :: Nil) // op(l, r)
964964
else // l.op(r), or val x = r; l.op(x), plus handle named args specially
965965
makeBinop(l, op, r)
966966
case PostfixOp(t, op) =>
967-
if ((ctx.mode is Mode.Type) && op == nme.raw.STAR) {
967+
if ((ctx.mode is Mode.Type) && !op.isBackquoted && op.name == nme.raw.STAR) {
968968
val seqType = if (ctx.compilationUnit.isJava) defn.ArrayType else defn.SeqType
969969
Annotated(
970970
AppliedTypeTree(ref(seqType), t),
971971
New(ref(defn.RepeatedAnnotType), Nil :: Nil))
972972
} else {
973973
assert(ctx.mode.isExpr || ctx.reporter.hasErrors, ctx.mode)
974-
Select(t, op)
974+
Select(t, op.name)
975975
}
976976
case PrefixOp(op, t) =>
977-
Select(t, nme.UNARY_PREFIX ++ op)
977+
Select(t, nme.UNARY_PREFIX ++ op.name)
978978
case Parens(t) =>
979979
t
980980
case Tuple(ts) =>

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,10 +334,15 @@ object Trees {
334334
extends RefTree[T] {
335335
type ThisTree[-T >: Untyped] = Ident[T]
336336
def qualifier: Tree[T] = genericEmptyTree
337+
338+
/** Is this a `BackquotedIdent` ? */
339+
def isBackquoted: Boolean = false
337340
}
338341

339342
class BackquotedIdent[-T >: Untyped] private[ast] (name: Name)
340343
extends Ident[T](name) {
344+
override def isBackquoted: Boolean = true
345+
341346
override def toString = s"BackquotedIdent($name)"
342347
}
343348

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
1515
// ----- Tree cases that exist in untyped form only ------------------
1616

1717
trait OpTree extends Tree {
18-
def op: Name
19-
override def isTerm = op.isTermName
20-
override def isType = op.isTypeName
18+
def op: Ident
19+
override def isTerm = op.name.isTermName
20+
override def isType = op.name.isTypeName
2121
}
2222

2323
/** A typed subtree of an untyped tree needs to be wrapped in a TypedSlice
@@ -66,9 +66,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
6666
*/
6767
class WildcardFunction(placeholderParams: List[ValDef], body: Tree) extends Function(placeholderParams, body)
6868

69-
case class InfixOp(left: Tree, op: Name, right: Tree) extends OpTree
70-
case class PostfixOp(od: Tree, op: Name) extends OpTree
71-
case class PrefixOp(op: Name, od: Tree) extends OpTree
69+
case class InfixOp(left: Tree, op: Ident, right: Tree) extends OpTree
70+
case class PostfixOp(od: Tree, op: Ident) extends OpTree
71+
case class PrefixOp(op: Ident, od: Tree) extends OpTree
7272
case class Parens(t: Tree) extends ProxyTree {
7373
def forwardTo = t
7474
}
@@ -409,15 +409,15 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
409409
case tree: Function if (args eq tree.args) && (body eq tree.body) => tree
410410
case _ => untpd.Function(args, body).withPos(tree.pos)
411411
}
412-
def InfixOp(tree: Tree)(left: Tree, op: Name, right: Tree) = tree match {
412+
def InfixOp(tree: Tree)(left: Tree, op: Ident, right: Tree) = tree match {
413413
case tree: InfixOp if (left eq tree.left) && (op eq tree.op) && (right eq tree.right) => tree
414414
case _ => untpd.InfixOp(left, op, right).withPos(tree.pos)
415415
}
416-
def PostfixOp(tree: Tree)(od: Tree, op: Name) = tree match {
416+
def PostfixOp(tree: Tree)(od: Tree, op: Ident) = tree match {
417417
case tree: PostfixOp if (od eq tree.od) && (op eq tree.op) => tree
418418
case _ => untpd.PostfixOp(od, op).withPos(tree.pos)
419419
}
420-
def PrefixOp(tree: Tree)(op: Name, od: Tree) = tree match {
420+
def PrefixOp(tree: Tree)(op: Ident, od: Tree) = tree match {
421421
case tree: PrefixOp if (op eq tree.op) && (od eq tree.od) => tree
422422
case _ => untpd.PrefixOp(op, od).withPos(tree.pos)
423423
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ object JavaParsers {
448448
if (in.token == DOTDOTDOT) {
449449
in.nextToken()
450450
t = atPos(t.pos.start) {
451-
PostfixOp(t, nme.raw.STAR)
451+
PostfixOp(t, Ident(nme.raw.STAR))
452452
}
453453
}
454454
atPos(start, in.offset) {

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

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ object Parsers {
3030
import reporting.diagnostic.Message
3131
import reporting.diagnostic.messages._
3232

33-
case class OpInfo(operand: Tree, operator: Name, offset: Offset)
33+
case class OpInfo(operand: Tree, operator: Ident, offset: Offset)
3434

3535
class ParensCounters {
3636
private var parCounts = new Array[Int](lastParen - firstParen)
@@ -414,18 +414,17 @@ object Parsers {
414414
"left- and right-associative operators with same precedence may not be mixed", offset)
415415

416416
def reduceStack(base: List[OpInfo], top: Tree, prec: Int, leftAssoc: Boolean): Tree = {
417-
if (opStack != base && precedence(opStack.head.operator) == prec)
418-
checkAssoc(opStack.head.offset, opStack.head.operator, leftAssoc)
417+
if (opStack != base && precedence(opStack.head.operator.name) == prec)
418+
checkAssoc(opStack.head.offset, opStack.head.operator.name, leftAssoc)
419419
def recur(top: Tree): Tree = {
420420
if (opStack == base) top
421421
else {
422422
val opInfo = opStack.head
423-
val opPrec = precedence(opInfo.operator)
423+
val opPrec = precedence(opInfo.operator.name)
424424
if (prec < opPrec || leftAssoc && prec == opPrec) {
425425
opStack = opStack.tail
426426
recur {
427-
val opPos = Position(opInfo.offset, opInfo.offset + opInfo.operator.length, opInfo.offset)
428-
atPos(opPos union opInfo.operand.pos union top.pos) {
427+
atPos(opInfo.operator.pos union opInfo.operand.pos union top.pos) {
429428
InfixOp(opInfo.operand, opInfo.operator, top)
430429
}
431430
}
@@ -449,10 +448,9 @@ object Parsers {
449448
val base = opStack
450449
var top = first
451450
while (isIdent && in.name != notAnOperator) {
452-
val op = if (isType) in.name.toTypeName else in.name
453-
top = reduceStack(base, top, precedence(op), isLeftAssoc(op))
451+
val op = if (isType) typeIdent() else termIdent()
452+
top = reduceStack(base, top, precedence(op.name), isLeftAssoc(op.name))
454453
opStack = OpInfo(top, op, in.offset) :: opStack
455-
ident()
456454
newLineOptWhenFollowing(canStartOperand)
457455
if (maybePostfix && !canStartOperand(in.token)) {
458456
val topInfo = opStack.head
@@ -870,7 +868,7 @@ object Parsers {
870868
val t = toplevelTyp()
871869
if (isIdent(nme.raw.STAR)) {
872870
in.nextToken()
873-
atPos(startOffset(t)) { PostfixOp(t, nme.raw.STAR) }
871+
atPos(startOffset(t)) { PostfixOp(t, Ident(nme.raw.STAR)) }
874872
} else t
875873
}
876874

@@ -1189,11 +1187,11 @@ object Parsers {
11891187
val prefixExpr = () =>
11901188
if (isIdent && nme.raw.isUnary(in.name)) {
11911189
val start = in.offset
1192-
val name = ident()
1193-
if (name == nme.raw.MINUS && isNumericLit)
1190+
val op = termIdent()
1191+
if (op.name == nme.raw.MINUS && isNumericLit)
11941192
simpleExprRest(literal(start), canApply = true)
11951193
else
1196-
atPos(start) { PrefixOp(name, simpleExpr()) }
1194+
atPos(start) { PrefixOp(op, simpleExpr()) }
11971195
}
11981196
else simpleExpr()
11991197

@@ -1260,7 +1258,7 @@ object Parsers {
12601258
val app = atPos(startOffset(t), in.offset) { Apply(t, argumentExprs()) }
12611259
simpleExprRest(app, canApply = true)
12621260
case USCORE =>
1263-
atPos(startOffset(t), in.skipToken()) { PostfixOp(t, nme.WILDCARD) }
1261+
atPos(startOffset(t), in.skipToken()) { PostfixOp(t, Ident(nme.WILDCARD)) }
12641262
case _ =>
12651263
t
12661264
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
516516
argsText ~ " => " ~ toText(body)
517517
}
518518
case InfixOp(l, op, r) =>
519-
val opPrec = parsing.precedence(op)
519+
val opPrec = parsing.precedence(op.name)
520520
changePrec(opPrec) { toText(l) ~ " " ~ toText(op) ~ " " ~ toText(r) }
521521
case PostfixOp(l, op) =>
522522
changePrec(InfixPrec) { toText(l) ~ " " ~ toText(op) }

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,8 +1077,6 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {
10771077

10781078
trait MatchTranslator extends TreeMakers with ScalacPatternExpanders {
10791079

1080-
def isBackquoted(x: Ident) = x.isInstanceOf[BackquotedIdent]
1081-
10821080
def isVarPattern(pat: Tree): Boolean = pat match {
10831081
case x: BackquotedIdent => false
10841082
case x: Ident => x.name.isVariableName

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ object EtaExpansion {
144144
ids = ids.init :+ repeated(ids.last)
145145
var body: Tree = Apply(lifted, ids)
146146
mt.resultType match {
147-
case rt: MethodType if !rt.isImplicit => body = PostfixOp(body, nme.WILDCARD)
147+
case rt: MethodType if !rt.isImplicit => body = PostfixOp(body, Ident(nme.WILDCARD))
148148
case _ =>
149149
}
150150
val fn = untpd.Function(params, body)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
object Test {
2+
type `&`[L,R] = L
3+
val x: Int `&` String = 10
4+
}

0 commit comments

Comments
 (0)