Skip to content

Commit

Permalink
Fix point for span
Browse files Browse the repository at this point in the history
  • Loading branch information
som-snytt committed Apr 13, 2024
1 parent a06f109 commit ee24067
Show file tree
Hide file tree
Showing 14 changed files with 64 additions and 51 deletions.
64 changes: 40 additions & 24 deletions src/reflect/scala/reflect/internal/Positions.scala
Expand Up @@ -46,23 +46,35 @@ trait Positions extends api.Positions { self: SymbolTable =>
* Otherwise returns default position that is either focused or not.
*/
def wrappingPos(default: Position, trees: List[Tree]): Position = wrappingPos(default, trees, focus = true)
def wrappingPos(default: Position, trees: List[Tree], focus: Boolean): Position = {
if (useOffsetPositions) default else {
val accum = new WrappingPosAccumulator()
var rest = trees
while (rest ne Nil) {
val head = rest.head
rest = rest.tail
// TODO: a tree's range position should cover the positions of all trees it "includes"
// (inclusion mostly refers to subtrees, but also other attributes reached through the tree, such as its annotations/modifiers);
// concretely, a MemberDef's position should cover its annotations (scala/bug#11060)
// Workaround, which explicitly includes annotations of traversed trees, can be removed when TODO above is resolved:
head match { case md: MemberDef => rest = md.mods.annotations ::: rest case _ => }

/** If the default point falls outside the calculated range, widen the result to include it.
*/
def wideningPos(default: Position, trees: List[Tree]): Position = {
val res = wrappingPos(default, trees)
val pointed = default.isDefined && default.start <= default.point && default.point <= default.end // has a point
if (pointed && (default.point < res.start || default.point > res.end)) {
val start = Math.min(res.start, default.point)
val end = Math.max(res.end, default.point)
Position.range(default.source, start = start, point = default.point, end = end)
}
else res
}
def wrappingPos(default: Position, trees: List[Tree], focus: Boolean): Position = if (useOffsetPositions) default else {
// TODO: a tree's range position should cover the positions of all trees it "includes"
// (inclusion mostly refers to subtrees, but also other attributes reached through the tree, such as its annotations/modifiers);
// concretely, a MemberDef's position should cover its annotations (scala/bug#11060)
// Workaround, which explicitly includes annotations of traversed trees, can be removed when TODO above is resolved:
val accum = new WrappingPosAccumulator()
def loop(trees: List[Tree]): Position = trees match {
case head :: rest =>
accum(head)
}
accum.result(default, focus)
head match {
case md: MemberDef => loop(md.mods.annotations ::: rest)
case _ => loop(rest)
}
case _ => accum.result(default, focus)
}
loop(trees)
}
private final class WrappingPosAccumulator extends (Tree => Boolean) {
private[this] var min: Int = _
Expand All @@ -72,11 +84,16 @@ trait Positions extends api.Positions { self: SymbolTable =>
max = Int.MinValue
}
reset()
def result(default: Position, focus: Boolean): Position = {
if (min > max)
if (focus) default.focus else default //there are no ranges
else Position.range(default.source, min, default.pointOrElse(min), max)
}
def result(default: Position, focus: Boolean): Position =
if (min > max) // there are no ranges
if (focus) default.focus else default
else { // ignore default.point not included by range min..max
val pointed = default.isDefined && default.start <= default.point && default.point <= default.end // has a point
val point =
if (pointed && min <= default.point && default.point <= max) default.point
else min
Position.range(default.source, start = min, point = point, end = max)
}
override def apply(v1: Tree): Boolean = {
val pos = v1.pos
if (pos.isRange) {
Expand All @@ -103,9 +120,8 @@ trait Positions extends api.Positions { self: SymbolTable =>
* shortening the range, assigning TransparentPositions
* to some of the nodes in `tree` or focusing on the position.
*/
def ensureNonOverlapping(tree: Tree, others: List[Tree]): Unit ={ ensureNonOverlapping(tree, others, focus = true) }
def ensureNonOverlapping(tree: Tree, others: List[Tree], focus: Boolean): Unit = {
if (useOffsetPositions) return
def ensureNonOverlapping(tree: Tree, others: List[Tree]): Unit = ensureNonOverlapping(tree, others, focus = true)
def ensureNonOverlapping(tree: Tree, others: List[Tree], focus: Boolean): Unit = if (!useOffsetPositions) {

def isOverlapping(pos: Position) =
pos.isRange && (others exists (pos overlaps _.pos))
Expand Down Expand Up @@ -305,15 +321,15 @@ trait Positions extends api.Positions { self: SymbolTable =>
def set(pos: Position, parent: Tree): Unit = {
wrappingPosAccumulator.reset()
this.pos = pos
try parent.foreachChild(this)
try parent.foreachChild(apply)
finally {
this.pos = null
}
}
def apply(tree: Tree): Boolean = {
wrappingPosAccumulator.reset()
if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) {
tree.foreachChild(this)
tree.foreachChild(apply)
tree.foreachChild(wrappingPosAccumulator)
val wrappingPos = wrappingPosAccumulator.result(pos, focus = true)
tree setPos wrappingPos
Expand Down
7 changes: 2 additions & 5 deletions src/reflect/scala/reflect/internal/TreeGen.scala
Expand Up @@ -423,13 +423,10 @@ abstract class TreeGen {
if (vparamss1.isEmpty || !vparamss1.head.isEmpty && vparamss1.head.head.mods.isImplicit)
vparamss1 = List() :: vparamss1
val superCall = pendingSuperCall // we can't know in advance which of the parents will end up as a superclass
// this requires knowing which of the parents is a type macro and which is not
// and that's something that cannot be found out before typer
// (the type macros aren't in the trunk yet, but there is a plan for them to land there soon)
// this means that we don't know what will be the arguments of the super call
// therefore here we emit a dummy which gets populated when the template is named and typechecked
// here we emit a dummy which gets populated when the template is named and typechecked
Some(
atPos(wrappingPos(superPos, lvdefs ::: vparamss1.flatten).makeTransparent) (
atPos(wideningPos(superPos, lvdefs ::: vparamss1.flatten).makeTransparent) (
DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(lvdefs ::: List(superCall), mkLiteralUnit))))
}
}
Expand Down
4 changes: 2 additions & 2 deletions test/files/neg/annots-constant-neg.check
Expand Up @@ -3,7 +3,7 @@ Test.scala:12: error: class Ann1 cannot have auxiliary constructors because it e
^
Test.scala:14: error: class Ann2 needs to have exactly one argument list because it extends ConstantAnnotation
class Ann2(x: Int)(y: Int) extends ConstantAnnotation // err
^
^
Test.scala:27: error: annotation argument needs to be a constant; found: Test.this.nonConst
@JAnn(nonConst) def t3 = 0 // err
^
Expand Down Expand Up @@ -68,7 +68,7 @@ Test.scala:66: error: annotation argument needs to be a constant; found: java.la
Test.scala:69: error: Java annotation SuppressWarnings is abstract; cannot be instantiated
Error occurred in an application involving default arguments.
@Ann(value = 0, c = Array(new SuppressWarnings(value = Array("")))) def u17 = 0 // err
^
^
Test.scala:69: error: not found: value value
Error occurred in an application involving default arguments.
@Ann(value = 0, c = Array(new SuppressWarnings(value = Array("")))) def u17 = 0 // err
Expand Down
4 changes: 2 additions & 2 deletions test/files/neg/java-annotation-bad.check
Expand Up @@ -3,13 +3,13 @@ Test_1.scala:12: error: Java annotation Ann_0 is abstract; cannot be instantiate
^
Test_1.scala:13: error: Java annotation Ann_0 is abstract; cannot be instantiated
val b: Ann_0 = new Ann_0(Array()) // nok
^
^
Test_1.scala:14: error: Java annotation Ann_1 is abstract; cannot be instantiated
val c: Ann_1 = new Ann_1 // nok
^
Test_1.scala:15: error: Java annotation Ann_1 is abstract; cannot be instantiated
val d: Ann_1 = new Ann_1(Array()) // nok
^
^
Test_1.scala:18: error: type mismatch;
found : ann.Ann_0
required: scala.annotation.Annotation
Expand Down
2 changes: 1 addition & 1 deletion test/files/neg/protected-constructors.check
Expand Up @@ -15,7 +15,7 @@ protected-constructors.scala:18: error: constructor Foo2 in class Foo2 cannot be
enclosing object P in package hungus is not a subclass of
class Foo2 in package dingus where target is defined
val foo2 = new Foo2("abc")
^
^
protected-constructors.scala:19: error: class Foo3 in object Ding cannot be accessed as a member of object dingus.Ding from object P in package hungus
Access to protected class Foo3 not permitted because
enclosing object P in package hungus is not a subclass of
Expand Down
2 changes: 1 addition & 1 deletion test/files/neg/t10514.check
Expand Up @@ -4,7 +4,7 @@ argument expression's type is not compatible with formal parameter type;
found : Some[C[Foo[Option,Test.this.Id]]]
required: ?F[C[?G[Foo[?F,?G]]]]
new Foo(Some(new C(new Foo[Option, Id](None))))
^
^
t10514.scala:8: error: type mismatch;
found : Some[C[Foo[Option,Test.this.Id]]]
required: F[C[G[Foo[F,G]]]]
Expand Down
2 changes: 1 addition & 1 deletion test/files/neg/t12155.check
@@ -1,4 +1,4 @@
t12155.scala:6: error: class Node in class C1 cannot be accessed as a member of C1[A,_$1] from package <empty>
class D[A, C](val x: C1[A, _]#Node[C]) {
^
^
1 error
2 changes: 1 addition & 1 deletion test/files/neg/t4987.check
@@ -1,4 +1,4 @@
t4987.scala:2: error: constructor Foo2 in class Foo2 cannot be accessed in object Bar2 from object Bar2
object Bar2 { new Foo2(0, 0) }
^
^
1 error
12 changes: 6 additions & 6 deletions test/files/neg/t5696.check
@@ -1,19 +1,19 @@
t5696.scala:6: error: too many argument lists for constructor invocation
new G(1)(2) {}
^
^
t5696.scala:14: error: too many argument lists for constructor invocation
new G()(2) {}
^
^
t5696.scala:22: error: too many argument lists for constructor invocation
new G[Int]()(2) {}
^
^
t5696.scala:30: error: too many argument lists for constructor invocation
new G[Int]()(2)(3) {}
^
^
t5696.scala:38: error: too many argument lists for constructor invocation
new G[Int]()()(2) {}
^
^
t5696.scala:46: error: too many argument lists for constructor invocation
object x extends G(1)(2) {}
^
^
6 errors
2 changes: 1 addition & 1 deletion test/files/neg/t6601.check
@@ -1,4 +1,4 @@
AccessPrivateConstructor_2.scala:2: error: constructor PrivateConstructor in class PrivateConstructor cannot be accessed in class AccessPrivateConstructor from class AccessPrivateConstructor
new PrivateConstructor("") // Scalac should forbid accessing to the private constructor!
^
^
1 error
2 changes: 1 addition & 1 deletion test/files/neg/t8685.check
Expand Up @@ -27,7 +27,7 @@ t8685.scala:50: warning: class C is deprecated (since now): class C is depr
^
t8685.scala:51: warning: constructor D in class D is deprecated (since now): ctor D is depr
def g = new D(42)
^
^
t8685.scala:52: warning: class E is deprecated (since now): class E is depr
def h = new E(42)
^
Expand Down
4 changes: 2 additions & 2 deletions test/files/run/t5603.check
Expand Up @@ -10,10 +10,10 @@
[87:209]class C extends [94:209][151:159]Greeting {
[119:139]val nameElse = _;
[95:101]<paramaccessor> private[this] val i: [98:101]Int = _;
<95:139>def <init>(<95:101>i: [98]Int) = <95:139>{
<94:139>def <init>(<95:101>i: [98]Int) = <94:139>{
<119:139>val nameElse = <134:139>"Bob";
[NoPosition][NoPosition][NoPosition]super.<init>();
<95:139>()
<94:139>()
};
[168:184]val name = [179:184]"avc";
[191:203][191:198]println([199:202]msg)
Expand Down
6 changes: 3 additions & 3 deletions test/files/run/t6288.check
Expand Up @@ -21,7 +21,7 @@
[89][89]case6()
};
[64:66]case6(){
[122:145][122]matchEnd4([122]throw [128][128][128]new [132]scala.MatchError([143]x1))
[122:145][122]matchEnd4([122]throw [128][132][132]new [132]scala.MatchError([143]x1))
};
[64:66]matchEnd4(x: [NoPosition]Unit){
[64:66]x
Expand Down Expand Up @@ -49,7 +49,7 @@
[246][246]case6()
};
[221:223]case6(){
[279:302][279]matchEnd4([279]throw [285][285][285]new [289]scala.MatchError([300]x1))
[279:302][279]matchEnd4([279]throw [285][289][289]new [289]scala.MatchError([300]x1))
};
[221:223]matchEnd4(x: [NoPosition]Unit){
[221:223]x
Expand Down Expand Up @@ -77,7 +77,7 @@
[390][390]case6()
};
[365:367]case6(){
[419:442][419]matchEnd4([419]throw [425][425][425]new [429]scala.MatchError([440]x1))
[419:442][419]matchEnd4([419]throw [425][429][429]new [429]scala.MatchError([440]x1))
};
[365:367]matchEnd4(x: [NoPosition]Unit){
[365:367]x
Expand Down
2 changes: 1 addition & 1 deletion test/tasty/neg/src-2/TestGenericTuples.check
Expand Up @@ -15,7 +15,7 @@ TestGenericTuples_fail.scala:10: error: Unsupported Scala 3 generic tuple type s
^
TestGenericTuples_fail.scala:11: error: Unsupported Scala 3 generic tuple type scala.Tuple in parameter value t; found in parameter t in class tastytest.GenericTuples.ConsumeTuple.
val test8 = new GenericTuples.ConsumeTuple(???) // error
^
^
TestGenericTuples_fail.scala:12: error: Unsupported Scala 3 generic tuple type scala.Tuple in bounds of type T; found in class tastytest.GenericTuples.ConsumeTupleGen.
val test9 = new GenericTuples.ConsumeTupleGen[(Int, String)](???) // error
^
Expand Down

0 comments on commit ee24067

Please sign in to comment.