Skip to content

Commit 40c1913

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 3588832 commit 40c1913

File tree

2 files changed

+64
-31
lines changed

2 files changed

+64
-31
lines changed

compiler/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
*
@@ -728,7 +736,7 @@ object Parsers {
728736

729737
def refinedTypeRest(t: Tree): Tree = {
730738
newLineOptWhenFollowedBy(LBRACE)
731-
if (in.token == LBRACE) refinedTypeRest(atPos(t.pos.start) { RefinedTypeTree(t, refinement()) })
739+
if (in.token == LBRACE) refinedTypeRest(atPos(startPos(t)) { RefinedTypeTree(t, refinement()) })
732740
else t
733741
}
734742

@@ -749,7 +757,7 @@ object Parsers {
749757
def annotType(): Tree = annotTypeRest(simpleType())
750758

751759
def annotTypeRest(t: Tree): Tree =
752-
if (in.token == AT) annotTypeRest(atPos(t.pos.start) { Annotated(t, annot()) })
760+
if (in.token == AT) annotTypeRest(atPos(startPos(t)) { Annotated(t, annot()) })
753761
else t
754762

755763
/** SimpleType ::= SimpleType TypeArgs
@@ -780,19 +788,19 @@ object Parsers {
780788
val handleSingletonType: Tree => Tree = t =>
781789
if (in.token == TYPE) {
782790
in.nextToken()
783-
atPos(t.pos.start) { SingletonTypeTree(t) }
791+
atPos(startPos(t)) { SingletonTypeTree(t) }
784792
} else t
785793

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

792800
private def typeProjection(t: Tree): Tree = {
793801
accept(HASH)
794802
val id = typeIdent()
795-
atPos(t.pos.start, id.pos.start) { Select(t, id.name) }
803+
atPos(startPos(t), startPos(id)) { Select(t, id.name) }
796804
}
797805

798806
/** NamedTypeArg ::= id `=' Type
@@ -846,7 +854,7 @@ object Parsers {
846854
val t = toplevelTyp()
847855
if (isIdent(nme.raw.STAR)) {
848856
in.nextToken()
849-
atPos(t.pos.start) { PostfixOp(t, nme.raw.STAR) }
857+
atPos(startPos(t)) { PostfixOp(t, nme.raw.STAR) }
850858
} else t
851859
}
852860

@@ -971,7 +979,7 @@ object Parsers {
971979
val t = expr1(location)
972980
if (in.token == ARROW) {
973981
placeholderParams = saved
974-
closureRest(t.pos.start, location, convertToParams(t))
982+
closureRest(startPos(t), location, convertToParams(t))
975983
}
976984
else if (isWildcard(t)) {
977985
placeholderParams = placeholderParams ::: saved
@@ -1025,7 +1033,7 @@ object Parsers {
10251033
assert(handlerStart != -1)
10261034
syntaxError(
10271035
new EmptyCatchBlock(body),
1028-
Position(handlerStart, handler.pos.end)
1036+
Position(handlerStart, endPos(handler))
10291037
)
10301038
case _ =>
10311039
}
@@ -1035,7 +1043,7 @@ object Parsers {
10351043
else {
10361044
if (handler.isEmpty) warning(
10371045
EmptyCatchAndFinallyBlock(body),
1038-
source atPos Position(tryOffset, body.pos.end)
1046+
source atPos Position(tryOffset, endPos(body))
10391047
)
10401048
EmptyTree
10411049
}
@@ -1057,21 +1065,21 @@ object Parsers {
10571065
case EQUALS =>
10581066
t match {
10591067
case Ident(_) | Select(_, _) | Apply(_, _) =>
1060-
atPos(t.pos.start, in.skipToken()) { Assign(t, expr()) }
1068+
atPos(startPos(t), in.skipToken()) { Assign(t, expr()) }
10611069
case _ =>
10621070
t
10631071
}
10641072
case COLON =>
10651073
ascription(t, location)
10661074
case MATCH =>
1067-
atPos(t.pos.start, in.skipToken()) {
1075+
atPos(startPos(t), in.skipToken()) {
10681076
inBraces(Match(t, caseClauses()))
10691077
}
10701078
case _ =>
10711079
t
10721080
}
10731081

1074-
def ascription(t: Tree, location: Location.Value) = atPos(t.pos.start, in.skipToken()) {
1082+
def ascription(t: Tree, location: Location.Value) = atPos(startPos(t), in.skipToken()) {
10751083
in.token match {
10761084
case USCORE =>
10771085
val uscoreStart = in.skipToken()
@@ -1105,7 +1113,7 @@ object Parsers {
11051113
val id = termIdent()
11061114
val paramExpr =
11071115
if (location == Location.InBlock && in.token == COLON)
1108-
atPos(id.pos.start, in.skipToken()) { Typed(id, infixType()) }
1116+
atPos(startPos(id), in.skipToken()) { Typed(id, infixType()) }
11091117
else
11101118
id
11111119
closureRest(start, location, convertToParam(paramExpr, mods) :: Nil)
@@ -1194,13 +1202,13 @@ object Parsers {
11941202
in.nextToken()
11951203
simpleExprRest(selector(t), canApply = true)
11961204
case LBRACKET =>
1197-
val tapp = atPos(t.pos.start, in.offset) { TypeApply(t, typeArgs(namedOK = true)) }
1205+
val tapp = atPos(startPos(t), in.offset) { TypeApply(t, typeArgs(namedOK = true)) }
11981206
simpleExprRest(tapp, canApply = true)
11991207
case LPAREN | LBRACE if canApply =>
1200-
val app = atPos(t.pos.start, in.offset) { Apply(t, argumentExprs()) }
1208+
val app = atPos(startPos(t), in.offset) { Apply(t, argumentExprs()) }
12011209
simpleExprRest(app, canApply = true)
12021210
case USCORE =>
1203-
atPos(t.pos.start, in.skipToken()) { PostfixOp(t, nme.WILDCARD) }
1211+
atPos(startPos(t), in.skipToken()) { PostfixOp(t, nme.WILDCARD) }
12041212
case _ =>
12051213
t
12061214
}
@@ -1284,7 +1292,7 @@ object Parsers {
12841292
if (in.token == IF) guard()
12851293
else {
12861294
val pat = pattern1()
1287-
if (in.token == EQUALS) atPos(pat.pos.start, in.skipToken()) { GenAlias(pat, expr()) }
1295+
if (in.token == EQUALS) atPos(startPos(pat), in.skipToken()) { GenAlias(pat, expr()) }
12881296
else generatorRest(pat)
12891297
}
12901298

@@ -1293,7 +1301,7 @@ object Parsers {
12931301
def generator(): Tree = generatorRest(pattern1())
12941302

12951303
def generatorRest(pat: Tree) =
1296-
atPos(pat.pos.start, accept(LARROW)) { GenFrom(pat, expr()) }
1304+
atPos(startPos(pat), accept(LARROW)) { GenFrom(pat, expr()) }
12971305

12981306
/** ForExpr ::= `for' (`(' Enumerators `)' | `{' Enumerators `}')
12991307
* {nl} [`yield'] Expr
@@ -1357,7 +1365,7 @@ object Parsers {
13571365
val pattern = () => {
13581366
val pat = pattern1()
13591367
if (isIdent(nme.raw.BAR))
1360-
atPos(pat.pos.start) { Alternative(pat :: patternAlts()) }
1368+
atPos(startPos(pat)) { Alternative(pat :: patternAlts()) }
13611369
else pat
13621370
}
13631371

@@ -1383,15 +1391,15 @@ object Parsers {
13831391
// compatibility for Scala2 `x @ _*` syntax
13841392
infixPattern() match {
13851393
case pt @ Ident(tpnme.WILDCARD_STAR) =>
1386-
migrationWarningOrError("The syntax `x @ _*' is no longer supported; use `x : _*' instead", p.pos.start)
1387-
atPos(p.pos.start, offset) { Typed(p, pt) }
1394+
migrationWarningOrError("The syntax `x @ _*' is no longer supported; use `x : _*' instead", startPos(p))
1395+
atPos(startPos(p), offset) { Typed(p, pt) }
13881396
case p =>
1389-
atPos(p.pos.start, offset) { Bind(name, p) }
1397+
atPos(startPos(p), offset) { Bind(name, p) }
13901398
}
13911399
case p @ Ident(tpnme.WILDCARD_STAR) =>
13921400
// compatibility for Scala2 `_*` syntax
1393-
migrationWarningOrError("The syntax `_*' is no longer supported; use `x : _*' instead", p.pos.start)
1394-
atPos(p.pos.start) { Typed(Ident(nme.WILDCARD), p) }
1401+
migrationWarningOrError("The syntax `_*' is no longer supported; use `x : _*' instead", startPos(p))
1402+
atPos(startPos(p)) { Typed(Ident(nme.WILDCARD), p) }
13951403
case p =>
13961404
p
13971405
}
@@ -1415,7 +1423,7 @@ object Parsers {
14151423
val simplePattern = () => in.token match {
14161424
case IDENTIFIER | BACKQUOTED_IDENT | THIS =>
14171425
path(thisOK = true) match {
1418-
case id @ Ident(nme.raw.MINUS) if isNumericLit => literal(id.pos.start)
1426+
case id @ Ident(nme.raw.MINUS) if isNumericLit => literal(startPos(id))
14191427
case t => simplePatternRest(t)
14201428
}
14211429
case USCORE =>
@@ -1445,9 +1453,9 @@ object Parsers {
14451453
def simplePatternRest(t: Tree): Tree = {
14461454
var p = t
14471455
if (in.token == LBRACKET)
1448-
p = atPos(t.pos.start, in.offset) { TypeApply(p, typeArgs()) }
1456+
p = atPos(startPos(t), in.offset) { TypeApply(p, typeArgs()) }
14491457
if (in.token == LPAREN)
1450-
p = atPos(t.pos.start, in.offset) { Apply(p, argumentPatterns()) }
1458+
p = atPos(startPos(t), in.offset) { Apply(p, argumentPatterns()) }
14511459
p
14521460
}
14531461

@@ -1573,7 +1581,8 @@ object Parsers {
15731581
case Select(qual, name) => cpy.Select(tree)(adjustStart(start)(qual), name)
15741582
case _ => tree
15751583
}
1576-
if (start < tree1.pos.start) tree1.withPos(tree1.pos.withStart(start))
1584+
if (tree1.pos.exists && start < tree1.pos.start)
1585+
tree1.withPos(tree1.pos.withStart(start))
15771586
else tree1
15781587
}
15791588

@@ -1804,7 +1813,7 @@ object Parsers {
18041813
def importSelector(): Tree = {
18051814
val from = termIdentOrWildcard()
18061815
if (from.name != nme.WILDCARD && in.token == ARROW)
1807-
atPos(from.pos.start, in.skipToken()) {
1816+
atPos(startPos(from), in.skipToken()) {
18081817
Thicket(from, termIdentOrWildcard())
18091818
}
18101819
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)