diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index cec7a72f3e8e..b77d86d24991 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -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 = @@ -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 `]' diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ee8aa668296d..d09597b9776a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -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 @@ -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: diff --git a/tests/neg/i18020.scala b/tests/neg/i18020.scala new file mode 100644 index 000000000000..b924c136d863 --- /dev/null +++ b/tests/neg/i18020.scala @@ -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 _ => ""