Skip to content

Commit 4c9002b

Browse files
committed
Refine followingIsGivenSig to not get confused by postfix as
1 parent 326ba1b commit 4c9002b

File tree

6 files changed

+67
-16
lines changed

6 files changed

+67
-16
lines changed

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

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ object Parsers {
8080
private val InCase: Region => Region = Scanners.InCase
8181
private val InCond: Region => Region = Scanners.InBraces
8282

83+
// TRANSITION
84+
val knownTypeNames: Set[TypeName] = Set(tpnme.AnyRef, tpnme.Object)
85+
8386
abstract class ParserCommon(val source: SourceFile)(using Context) {
8487

8588
val in: ScannerCommon
@@ -897,23 +900,68 @@ object Parsers {
897900
followedByToken(LARROW) // `<-` comes before possible statement starts
898901
}
899902

900-
/** Are the next token the "GivenSig" part of a given definition,
903+
/** Are the next token the "GivenSig" part of an old-style given definition,
901904
* i.e. an identifier followed by type and value parameters, followed by `:`?
902-
* @pre The current token is an identifier
903905
*/
904-
def followingIsGivenSig() =
906+
def followingIsGivenSig() = // TRANSITION
905907
val lookahead = in.LookaheadScanner()
908+
var prefixName = EmptyTermName
906909
if lookahead.isIdent then
910+
prefixName = lookahead.name
907911
lookahead.nextToken()
912+
var isOldStyle: Boolean = false
913+
def isParamStart = lookahead.token == LPAREN || lookahead.token == LBRACKET
908914
def skipParams(): Unit =
909-
if lookahead.token == LPAREN || lookahead.token == LBRACKET then
910-
lookahead.skipParens()
915+
if isParamStart then
916+
val opening = lookahead.token
917+
lookahead.nextToken()
918+
if prefixName.isEmpty
919+
&& (opening == LBRACKET || lookahead.isIdent(nme.using))
920+
then isOldStyle = true
921+
lookahead.skipParensRest(opening)
911922
skipParams()
912923
else if lookahead.isNewLine then
913924
lookahead.nextToken()
914925
skipParams()
926+
val prefixHasParams = isParamStart
915927
skipParams()
916-
lookahead.isIdent(nme.as)
928+
if !lookahead.isIdent(nme.as) then false
929+
else
930+
lookahead.nextToken()
931+
if isOldStyle || !lookahead.isIdent then
932+
true
933+
else
934+
val suffixName = lookahead.name
935+
lookahead.nextToken()
936+
if isParamStart || lookahead.token == DOT then
937+
true
938+
else if prefixName.isEmpty then
939+
// we have `given (...) as bar with no `using`; it must be new style
940+
false
941+
else if !prefixHasParams && prefixName == suffixName then
942+
// we have `given foo as foo`, so it does not matter how we interpret it
943+
true
944+
else if knownTypeNames.contains(suffixName.toTypeName) then
945+
true
946+
else if knownTypeNames.contains(prefixName.toTypeName) then
947+
true
948+
else
949+
// we have one of the following
950+
//
951+
// 1. given foo as bar
952+
// 2. given foo[...]... as bar
953+
// 3. given foo(...)... as bar
954+
//
955+
// Decide on the case of the names; lowercase means bound name
956+
957+
val prefixIsUpper = Character.isUpperCase(prefixName.head)
958+
val suffixIsUpper = Character.isUpperCase(suffixName.head)
959+
if prefixIsUpper && !suffixIsUpper then false
960+
else if !prefixIsUpper && suffixIsUpper then true
961+
else syntaxError(
962+
em"ambiguous syntax for given definition; make sure exactly one of $prefixName, $suffixName is capitalized")
963+
true
964+
end followingIsGivenSig
917965

918966
def followingIsExtension() =
919967
val next = in.lookahead.token

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,9 @@ object Scanners {
890890
final def skipParens(multiple: Boolean = true): Unit =
891891
val opening = token
892892
nextToken()
893+
skipParensRest(opening, multiple) // TRANSITION
894+
895+
final def skipParensRest(opening: Token, multiple: Boolean = true): Unit =
893896
while token != EOF && token != opening + 1 do
894897
if token == opening && multiple then skipParens() else nextToken()
895898
nextToken()

tests/disabled/pos/i7851.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ object Wrapper { type Aux[T <: Tuple, WrappedT0 <: Tuple] = Wrapper[T] { type Wr
88

99
given Wrapper[EmptyTuple] { type WrappedT = EmptyTuple }
1010

11-
given [T: Wrappable] as Wrapper[T] { type WrappedT = Wrapped[T] }
11+
given [T: Wrappable] => Wrapper[T] { type WrappedT = Wrapped[T] }
1212

1313
given [H: Wrappable, T <: Tuple, WrappedT0 <: Tuple]
14-
(using Wrapper.Aux[T, WrappedT0])
15-
as Wrapper[H *: T]:
14+
=> Wrapper.Aux[T, WrappedT0]
15+
=> Wrapper[H *: T]:
1616
type WrappedT = Wrapped[H] *: WrappedT0
1717

1818
def wrappedFunction[F, FArgs <: Tuple, WrapperFArgs <: Tuple, R: Wrappable](

tests/pos/i5915.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ trait RunDSL
22

33
val rdsl = new RunDSL {}
44

5-
given RunNNFExpr[B] as RunDSL = rdsl
5+
given runNNFExpr[B] as RunDSL = rdsl
66

7-
given RunNNFImpl[B] as RunDSL {
7+
given runNNFImpl[B] as RunDSL {
88
//override def runDSL(b: NNF[B]): B = b.terminal
99
}

tests/pos/i5978.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ package p3 {
8484
package p4 {
8585
class TC
8686

87-
given A as TC
87+
given a as TC
8888

89-
given B[X[_], Y] as TC
89+
given b[X[_], Y] as TC
9090

91-
given C(using TC) as TC
91+
given c(using TC) as TC
9292
}

tests/run/extmethod-overload.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ object Test extends App {
6161
extension [T](xs: List[T]) def +++ (ys: List[T]): List[T] = xs ++ ys ++ ys
6262
extension [T](xs: List[T]) def +++ (ys: Iterator[T]): List[T] = xs ++ ys ++ ys
6363
}
64-
given Bar as Foo
64+
given bar as Foo
6565

6666
assert((1 |+| 2) == 3)
6767
assert((1 |+| "2") == 2)
@@ -74,7 +74,7 @@ object Test extends App {
7474

7575
// Test with extension methods coming from given alias
7676
object test4 {
77-
given test3.Foo = test3.Bar
77+
given test3.Foo = test3.bar
7878

7979
assert((1 |+| 2) == 3)
8080
assert((1 |+| "2") == 2)

0 commit comments

Comments
 (0)