Skip to content

Commit 187eb65

Browse files
committed
More robust scheme for taking start/end of positions when parsing
Some trees, which do not consume input have unassigned positions (so that they can fit in whatever range they are integrated). It's therefore risky to take the start or end of a parsed tree's position. This commit guards against the case where the position of the tree does not exist.
1 parent adb37ee commit 187eb65

File tree

2 files changed

+64
-31
lines changed

2 files changed

+64
-31
lines changed

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

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ object Parsers {
8383
def atPos[T <: Positioned](start: Offset)(t: T): T =
8484
atPos(start, start)(t)
8585

86+
/** Defensive version of Position#start */
87+
def startPos(t: Positioned): Int =
88+
if (t.pos.exists) t.pos.start else in.offset
89+
90+
/** Defensive version of Position#end */
91+
def endPos(t: Positioned): Int =
92+
if (t.pos.exists) t.pos.end else in.lastOffset
93+
8694
def nameStart: Offset =
8795
if (in.token == BACKQUOTED_IDENT) in.offset + 1 else in.offset
8896

@@ -448,7 +456,7 @@ object Parsers {
448456
val topInfo = opStack.head
449457
opStack = opStack.tail
450458
val od = reduceStack(base, topInfo.operand, 0, true)
451-
return atPos(od.pos.start, topInfo.offset) {
459+
return atPos(startPos(od), topInfo.offset) {
452460
PostfixOp(od, topInfo.operator)
453461
}
454462
}
@@ -492,7 +500,7 @@ object Parsers {
492500

493501
/** Accept identifier acting as a selector on given tree `t`. */
494502
def selector(t: Tree): Tree =
495-
atPos(t.pos.start, in.offset) { Select(t, ident()) }
503+
atPos(startPos(t), in.offset) { Select(t, ident()) }
496504

497505
/** Selectors ::= ident { `.' ident()
498506
*
@@ -727,7 +735,7 @@ object Parsers {
727735

728736
def refinedTypeRest(t: Tree): Tree = {
729737
newLineOptWhenFollowedBy(LBRACE)
730-
if (in.token == LBRACE) refinedTypeRest(atPos(t.pos.start) { RefinedTypeTree(t, refinement()) })
738+
if (in.token == LBRACE) refinedTypeRest(atPos(startPos(t)) { RefinedTypeTree(t, refinement()) })
731739
else t
732740
}
733741

@@ -748,7 +756,7 @@ object Parsers {
748756
def annotType(): Tree = annotTypeRest(simpleType())
749757

750758
def annotTypeRest(t: Tree): Tree =
751-
if (in.token == AT) annotTypeRest(atPos(t.pos.start) { Annotated(t, annot()) })
759+
if (in.token == AT) annotTypeRest(atPos(startPos(t)) { Annotated(t, annot()) })
752760
else t
753761

754762
/** SimpleType ::= SimpleType TypeArgs
@@ -779,19 +787,19 @@ object Parsers {
779787
val handleSingletonType: Tree => Tree = t =>
780788
if (in.token == TYPE) {
781789
in.nextToken()
782-
atPos(t.pos.start) { SingletonTypeTree(t) }
790+
atPos(startPos(t)) { SingletonTypeTree(t) }
783791
} else t
784792

785793
private def simpleTypeRest(t: Tree): Tree = in.token match {
786794
case HASH => simpleTypeRest(typeProjection(t))
787-
case LBRACKET => simpleTypeRest(atPos(t.pos.start) { AppliedTypeTree(t, typeArgs(namedOK = true)) })
795+
case LBRACKET => simpleTypeRest(atPos(startPos(t)) { AppliedTypeTree(t, typeArgs(namedOK = true)) })
788796
case _ => t
789797
}
790798

791799
private def typeProjection(t: Tree): Tree = {
792800
accept(HASH)
793801
val id = typeIdent()
794-
atPos(t.pos.start, id.pos.start) { Select(t, id.name) }
802+
atPos(startPos(t), startPos(id)) { Select(t, id.name) }
795803
}
796804

797805
/** NamedTypeArg ::= id `=' Type
@@ -845,7 +853,7 @@ object Parsers {
845853
val t = toplevelTyp()
846854
if (isIdent(nme.raw.STAR)) {
847855
in.nextToken()
848-
atPos(t.pos.start) { PostfixOp(t, nme.raw.STAR) }
856+
atPos(startPos(t)) { PostfixOp(t, nme.raw.STAR) }
849857
} else t
850858
}
851859

@@ -970,7 +978,7 @@ object Parsers {
970978
val t = expr1(location)
971979
if (in.token == ARROW) {
972980
placeholderParams = saved
973-
closureRest(t.pos.start, location, convertToParams(t))
981+
closureRest(startPos(t), location, convertToParams(t))
974982
}
975983
else if (isWildcard(t)) {
976984
placeholderParams = placeholderParams ::: saved
@@ -1024,7 +1032,7 @@ object Parsers {
10241032
assert(handlerStart != -1)
10251033
syntaxError(
10261034
new EmptyCatchBlock(body),
1027-
Position(handlerStart, handler.pos.end)
1035+
Position(handlerStart, endPos(handler))
10281036
)
10291037
case _ =>
10301038
}
@@ -1034,7 +1042,7 @@ object Parsers {
10341042
else {
10351043
if (handler.isEmpty) warning(
10361044
EmptyCatchAndFinallyBlock(body),
1037-
source atPos Position(tryOffset, body.pos.end)
1045+
source atPos Position(tryOffset, endPos(body))
10381046
)
10391047
EmptyTree
10401048
}
@@ -1056,21 +1064,21 @@ object Parsers {
10561064
case EQUALS =>
10571065
t match {
10581066
case Ident(_) | Select(_, _) | Apply(_, _) =>
1059-
atPos(t.pos.start, in.skipToken()) { Assign(t, expr()) }
1067+
atPos(startPos(t), in.skipToken()) { Assign(t, expr()) }
10601068
case _ =>
10611069
t
10621070
}
10631071
case COLON =>
10641072
ascription(t, location)
10651073
case MATCH =>
1066-
atPos(t.pos.start, in.skipToken()) {
1074+
atPos(startPos(t), in.skipToken()) {
10671075
inBraces(Match(t, caseClauses()))
10681076
}
10691077
case _ =>
10701078
t
10711079
}
10721080

1073-
def ascription(t: Tree, location: Location.Value) = atPos(t.pos.start, in.skipToken()) {
1081+
def ascription(t: Tree, location: Location.Value) = atPos(startPos(t), in.skipToken()) {
10741082
in.token match {
10751083
case USCORE =>
10761084
val uscoreStart = in.skipToken()
@@ -1104,7 +1112,7 @@ object Parsers {
11041112
val id = termIdent()
11051113
val paramExpr =
11061114
if (location == Location.InBlock && in.token == COLON)
1107-
atPos(id.pos.start, in.skipToken()) { Typed(id, infixType()) }
1115+
atPos(startPos(id), in.skipToken()) { Typed(id, infixType()) }
11081116
else
11091117
id
11101118
closureRest(start, location, convertToParam(paramExpr, mods) :: Nil)
@@ -1193,13 +1201,13 @@ object Parsers {
11931201
in.nextToken()
11941202
simpleExprRest(selector(t), canApply = true)
11951203
case LBRACKET =>
1196-
val tapp = atPos(t.pos.start, in.offset) { TypeApply(t, typeArgs(namedOK = true)) }
1204+
val tapp = atPos(startPos(t), in.offset) { TypeApply(t, typeArgs(namedOK = true)) }
11971205
simpleExprRest(tapp, canApply = true)
11981206
case LPAREN | LBRACE if canApply =>
1199-
val app = atPos(t.pos.start, in.offset) { Apply(t, argumentExprs()) }
1207+
val app = atPos(startPos(t), in.offset) { Apply(t, argumentExprs()) }
12001208
simpleExprRest(app, canApply = true)
12011209
case USCORE =>
1202-
atPos(t.pos.start, in.skipToken()) { PostfixOp(t, nme.WILDCARD) }
1210+
atPos(startPos(t), in.skipToken()) { PostfixOp(t, nme.WILDCARD) }
12031211
case _ =>
12041212
t
12051213
}
@@ -1283,7 +1291,7 @@ object Parsers {
12831291
if (in.token == IF) guard()
12841292
else {
12851293
val pat = pattern1()
1286-
if (in.token == EQUALS) atPos(pat.pos.start, in.skipToken()) { GenAlias(pat, expr()) }
1294+
if (in.token == EQUALS) atPos(startPos(pat), in.skipToken()) { GenAlias(pat, expr()) }
12871295
else generatorRest(pat)
12881296
}
12891297

@@ -1292,7 +1300,7 @@ object Parsers {
12921300
def generator(): Tree = generatorRest(pattern1())
12931301

12941302
def generatorRest(pat: Tree) =
1295-
atPos(pat.pos.start, accept(LARROW)) { GenFrom(pat, expr()) }
1303+
atPos(startPos(pat), accept(LARROW)) { GenFrom(pat, expr()) }
12961304

12971305
/** ForExpr ::= `for' (`(' Enumerators `)' | `{' Enumerators `}')
12981306
* {nl} [`yield'] Expr
@@ -1356,7 +1364,7 @@ object Parsers {
13561364
val pattern = () => {
13571365
val pat = pattern1()
13581366
if (isIdent(nme.raw.BAR))
1359-
atPos(pat.pos.start) { Alternative(pat :: patternAlts()) }
1367+
atPos(startPos(pat)) { Alternative(pat :: patternAlts()) }
13601368
else pat
13611369
}
13621370

@@ -1382,15 +1390,15 @@ object Parsers {
13821390
// compatibility for Scala2 `x @ _*` syntax
13831391
infixPattern() match {
13841392
case pt @ Ident(tpnme.WILDCARD_STAR) =>
1385-
migrationWarningOrError("The syntax `x @ _*' is no longer supported; use `x : _*' instead", p.pos.start)
1386-
atPos(p.pos.start, offset) { Typed(p, pt) }
1393+
migrationWarningOrError("The syntax `x @ _*' is no longer supported; use `x : _*' instead", startPos(p))
1394+
atPos(startPos(p), offset) { Typed(p, pt) }
13871395
case p =>
1388-
atPos(p.pos.start, offset) { Bind(name, p) }
1396+
atPos(startPos(p), offset) { Bind(name, p) }
13891397
}
13901398
case p @ Ident(tpnme.WILDCARD_STAR) =>
13911399
// compatibility for Scala2 `_*` syntax
1392-
migrationWarningOrError("The syntax `_*' is no longer supported; use `x : _*' instead", p.pos.start)
1393-
atPos(p.pos.start) { Typed(Ident(nme.WILDCARD), p) }
1400+
migrationWarningOrError("The syntax `_*' is no longer supported; use `x : _*' instead", startPos(p))
1401+
atPos(startPos(p)) { Typed(Ident(nme.WILDCARD), p) }
13941402
case p =>
13951403
p
13961404
}
@@ -1414,7 +1422,7 @@ object Parsers {
14141422
val simplePattern = () => in.token match {
14151423
case IDENTIFIER | BACKQUOTED_IDENT | THIS =>
14161424
path(thisOK = true) match {
1417-
case id @ Ident(nme.raw.MINUS) if isNumericLit => literal(id.pos.start)
1425+
case id @ Ident(nme.raw.MINUS) if isNumericLit => literal(startPos(id))
14181426
case t => simplePatternRest(t)
14191427
}
14201428
case USCORE =>
@@ -1444,9 +1452,9 @@ object Parsers {
14441452
def simplePatternRest(t: Tree): Tree = {
14451453
var p = t
14461454
if (in.token == LBRACKET)
1447-
p = atPos(t.pos.start, in.offset) { TypeApply(p, typeArgs()) }
1455+
p = atPos(startPos(t), in.offset) { TypeApply(p, typeArgs()) }
14481456
if (in.token == LPAREN)
1449-
p = atPos(t.pos.start, in.offset) { Apply(p, argumentPatterns()) }
1457+
p = atPos(startPos(t), in.offset) { Apply(p, argumentPatterns()) }
14501458
p
14511459
}
14521460

@@ -1572,7 +1580,8 @@ object Parsers {
15721580
case Select(qual, name) => cpy.Select(tree)(adjustStart(start)(qual), name)
15731581
case _ => tree
15741582
}
1575-
if (start < tree1.pos.start) tree1.withPos(tree1.pos.withStart(start))
1583+
if (tree1.pos.exists && start < tree1.pos.start)
1584+
tree1.withPos(tree1.pos.withStart(start))
15761585
else tree1
15771586
}
15781587

@@ -1803,7 +1812,7 @@ object Parsers {
18031812
def importSelector(): Tree = {
18041813
val from = termIdentOrWildcard()
18051814
if (from.name != nme.WILDCARD && in.token == ARROW)
1806-
atPos(from.pos.start, in.skipToken()) {
1815+
atPos(startPos(from), in.skipToken()) {
18071816
Thicket(from, termIdentOrWildcard())
18081817
}
18091818
else from

tests/neg/i1705.scala

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
object DepBug {
2+
class A {
3+
class B
4+
def mkB = new B
5+
def m(b: B) = b
6+
}
7+
trait Dep {
8+
val a: A
9+
val b: a.B
10+
}
11+
val dep = new {
12+
val a = new A
13+
val b = a mkB
14+
}
15+
def useDep(d: Dep) { // error: procedure syntax
16+
import d._
17+
a m (b)
18+
}
19+
{ // error: Null does not take parameters (follow on)
20+
import dep._
21+
a m (b)
22+
}
23+
dep.a m (dep b) // error (follow on)
24+
}

0 commit comments

Comments
 (0)