Skip to content

Commit

Permalink
Disallow naming the root package, except for selections (#18187)
Browse files Browse the repository at this point in the history
References #18020, didn't actually fix that, because it addressed
aspects of using `_root_` in definitions. Adding more details to that
ticket.
Fixes #17757
Fixes #18050
Includes the code in scala/bug#12508
  • Loading branch information
smarter committed Jul 14, 2023
2 parents 9667958 + ba1354d commit ca29cdc
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 17 deletions.
33 changes: 19 additions & 14 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,10 @@ object Parsers {

/** Accept identifier and return Ident with its name as a term name. */
def termIdent(): Ident =
makeIdent(in.token, in.offset, ident())
val t = makeIdent(in.token, in.offset, ident())
if t.name == nme.ROOTPKG then
syntaxError(em"Illegal use of root package name.")
t

/** Accept identifier and return Ident with its name as a type name. */
def typeIdent(): Ident =
Expand Down Expand Up @@ -1128,19 +1131,21 @@ object Parsers {

if in.token == THIS then handleThis(EmptyTypeIdent)
else if in.token == SUPER then handleSuper(EmptyTypeIdent)
else
val t = termIdent()
if in.token == DOT then
def qual = cpy.Ident(t)(t.name.toTypeName)
in.lookahead.token match
case THIS =>
in.nextToken()
handleThis(qual)
case SUPER =>
in.nextToken()
handleSuper(qual)
case _ => t
else t
else if in.token != INTERPOLATIONID && in.lookahead.token == DOT then
val tok = in.token
val offset = in.offset
val name = ident()
def qual = makeIdent(tok, offset, name.toTypeName)
in.lookahead.token match
case THIS =>
in.nextToken()
handleThis(qual)
case SUPER =>
in.nextToken()
handleSuper(qual)
case _ =>
makeIdent(tok, offset, name)
else termIdent()
end simpleRef

/** MixinQualifier ::= `[' id `]'
Expand Down
8 changes: 5 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
// optimization, it also avoids forcing imports thus potentially avoiding
// cyclic references.
if (name == nme.ROOTPKG)
return tree.withType(defn.RootPackage.termRef)
val tree2 = tree.withType(defn.RootPackage.termRef)
checkLegalValue(tree2, pt)
return tree2

val rawType =
val saved1 = unimported
Expand All @@ -586,8 +588,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
foundUnderScala2
else found
finally
unimported = saved1
foundUnderScala2 = saved2
unimported = saved1
foundUnderScala2 = saved2

/** Normally, returns `ownType` except if `ownType` is a constructor proxy,
* and there is another shadowed type accessible with the same name that is not:
Expand Down
62 changes: 62 additions & 0 deletions tests/neg/i18020.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import _root_.scala.StringContext // ok

class Test :
val Foo = 1
def foo0: Unit =
val x = new _root_.scala.StringContext() // ok
val y: Option[_root_.scala.Serializable] = None // ok
val z: _root_.scala.None.type = None
val w = _root_.scala.None
val (_root_, other) = (1, 2) // error
val (Test.this.Foo, 1) = ???
??? match
case (Test.this.Foo, 1) => ()

def foo3 =
val _root_ = "abc" // error

def foo1: Unit =
val _root_: String = "abc" // error // error
// _root_: is, technically, a legal name
// so then it tries to construct the infix op pattern
// "_root_ String .." and then throws in a null when it fails
// to find an argument
// then Typer rejects "String" as an infix extractor (like ::)
// which is the second error

def foo2: Unit = // error
val _root_ : String = "abc" // error

// i17757
def fooVal: Unit =
val _root_ = "abc" // error
println(_root_.length) // error
println(_root_) // error

def barVal: Unit =
_root_ // error
_root_.scala // error
println(_root_) // error
println(_root_.scala) // error

// i18050
package p {
package _root_ { // error
object X // error
}
}

// scala/bug#12508
package _root_ { // error
class C {
val _root_ = 42 // error
}
}
package _root_.p { // error
class C
}

// from ScalaPB
def fromScalaPb(x: Option[String]) = x match
case _root_.scala.Some(s) => s
case _ => ""

0 comments on commit ca29cdc

Please sign in to comment.