Skip to content

Commit 99679cf

Browse files
authored
Merge pull request #1941 from dotty-staging/fix/infix-pos
Better positions for infix operations
2 parents de2c447 + b0576e9 commit 99679cf

File tree

11 files changed

+57
-43
lines changed

11 files changed

+57
-43
lines changed

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

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ object desugar {
353353
for (i <- 0 until arity if nme.selectorName(i) `ne` caseParams(i).name)
354354
yield syntheticProperty(nme.selectorName(i), Select(This(EmptyTypeIdent), caseParams(i).name))
355355
def isRepeated(tree: Tree): Boolean = tree match {
356-
case PostfixOp(_, nme.raw.STAR) => true
356+
case PostfixOp(_, Ident(nme.raw.STAR)) => true
357357
case ByNameTypeTree(tree1) => isRepeated(tree1)
358358
case _ => false
359359
}
@@ -739,23 +739,25 @@ 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+
val selectPos = Position(left.pos.start, op.pos.end, op.pos.start)
754+
Apply(Select(left, op.name).withPos(selectPos), args)
754755
} else {
755756
val x = ctx.freshName().toTermName
757+
val selectPos = Position(op.pos.start, right.pos.end, op.pos.start)
756758
new InfixOpBlock(
757759
ValDef(x, TypeTree(), left).withMods(synthetic),
758-
Apply(Select(right, op), Ident(x)))
760+
Apply(Select(right, op.name).withPos(selectPos), Ident(x).withPos(left.pos)))
759761
}
760762
}
761763

@@ -956,25 +958,25 @@ object desugar {
956958
Apply(Select(Apply(Ident(nme.StringContext), strs), id), elems)
957959
case InfixOp(l, op, r) =>
958960
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]
961+
if (!op.isBackquoted && op.name == tpnme.raw.AMP) AndTypeTree(l, r) // l & r
962+
else if (!op.isBackquoted && op.name == tpnme.raw.BAR) OrTypeTree(l, r) // l | r
963+
else AppliedTypeTree(op, l :: r :: Nil) // op[l, r]
962964
else if (ctx.mode is Mode.Pattern)
963-
Apply(Ident(op), l :: r :: Nil) // op(l, r)
965+
Apply(op, l :: r :: Nil) // op(l, r)
964966
else // l.op(r), or val x = r; l.op(x), plus handle named args specially
965967
makeBinop(l, op, r)
966968
case PostfixOp(t, op) =>
967-
if ((ctx.mode is Mode.Type) && op == nme.raw.STAR) {
969+
if ((ctx.mode is Mode.Type) && !op.isBackquoted && op.name == nme.raw.STAR) {
968970
val seqType = if (ctx.compilationUnit.isJava) defn.ArrayType else defn.SeqType
969971
Annotated(
970972
AppliedTypeTree(ref(seqType), t),
971973
New(ref(defn.RepeatedAnnotType), Nil :: Nil))
972974
} else {
973975
assert(ctx.mode.isExpr || ctx.reporter.hasErrors, ctx.mode)
974-
Select(t, op)
976+
Select(t, op.name)
975977
}
976978
case PrefixOp(op, t) =>
977-
Select(t, nme.UNARY_PREFIX ++ op)
979+
Select(t, nme.UNARY_PREFIX ++ op.name)
978980
case Parens(t) =>
979981
t
980982
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: 10 additions & 10 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
}
@@ -357,7 +357,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
357357
* parameter, the reference will be a repeated argument.
358358
*/
359359
def refOfDef(tree: MemberDef)(implicit ctx: Context) = tree match {
360-
case ValDef(_, PostfixOp(_, nme.raw.STAR), _) => repeated(Ident(tree.name))
360+
case ValDef(_, PostfixOp(_, Ident(nme.raw.STAR)), _) => repeated(Ident(tree.name))
361361
case _ => Ident(tree.name)
362362
}
363363

@@ -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)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,7 +1440,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
14401440

14411441

14421442
def typedAsFunction(tree: untpd.PostfixOp, pt: Type)(implicit ctx: Context): Tree = {
1443-
val untpd.PostfixOp(qual, nme.WILDCARD) = tree
1443+
val untpd.PostfixOp(qual, Ident(nme.WILDCARD)) = tree
14441444
val pt1 = if (defn.isFunctionType(pt)) pt else AnyFunctionProto
14451445
var res = typed(qual, pt1)
14461446
if (pt1.eq(AnyFunctionProto) && !defn.isFunctionClass(res.tpe.classSymbol)) {
@@ -1541,7 +1541,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
15411541
case tree: untpd.Annotated => typedAnnotated(tree, pt)
15421542
case tree: untpd.TypedSplice => typedTypedSplice(tree)
15431543
case tree: untpd.UnApply => typedUnApply(tree, pt)
1544-
case tree @ untpd.PostfixOp(qual, nme.WILDCARD) => typedAsFunction(tree, pt)
1544+
case tree @ untpd.PostfixOp(qual, Ident(nme.WILDCARD)) => typedAsFunction(tree, pt)
15451545
case untpd.EmptyTree => tpd.EmptyTree
15461546
case _ => typedUnadapted(desugar(tree), pt)
15471547
}
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+
}

tests/repl/errmsgs.check

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,11 @@ scala> class Foo() { def bar: Int = 1 }; val foo = new Foo(); foo.barr
7878
4 |class Foo() { def bar: Int = 1 }; val foo = new Foo(); foo.barr
7979
| ^^^^^^^^
8080
| value `barr` is not a member of Foo(foo) - did you mean `foo.bar`?
81+
scala> val x: List[Int] = "foo" :: List(1)
82+
-- [E007] Type Mismatch Error: <console> ---------------------------------------
83+
4 |val x: List[Int] = "foo" :: List(1)
84+
| ^^^^^
85+
| found: String($1$)
86+
| required: Int
87+
|
8188
scala> :quit

0 commit comments

Comments
 (0)