From bc07b0389c9753f3186fbb604ff2f6da9819dcd3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 12 May 2021 11:01:44 +0200 Subject: [PATCH 1/2] Disallow package names as types Fixes #12432 --- .../tools/dotc/transform/PostTyper.scala | 28 ++++++++++++------- tests/neg/i12432.scala | 4 +++ 2 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 tests/neg/i12432.scala diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 6f1e3b3f0319..17e54139d11c 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -263,6 +263,10 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case Select(qual, _) => check(qual) // simple select _n case Apply(TypeApply(Select(qual, _), _), _) => check(qual) // generic select .apply[T](n) + def checkNotPackage(tree: Tree)(using Context): Unit = + if tree.symbol.is(Package) then + report.error(i"${tree.symbol} cannot be used as a type", tree.srcPos) + override def transform(tree: Tree)(using Context): Tree = try tree match { // TODO move CaseDef case lower: keep most probable trees first for performance @@ -273,21 +277,25 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case None => ctx super.transform(tree)(using gadtCtx) - case tree: Ident if !tree.isType => - if tree.symbol.is(Inline) && !Inliner.inInlineMethod then - ctx.compilationUnit.needsInlining = true - checkNoConstructorProxy(tree) - tree.tpe match { - case tpe: ThisType => This(tpe.cls).withSpan(tree.span) - case _ => tree - } + case tree: Ident => + if tree.isType then + checkNotPackage(tree) + tree + else + if tree.symbol.is(Inline) && !Inliner.inInlineMethod then + ctx.compilationUnit.needsInlining = true + checkNoConstructorProxy(tree) + tree.tpe match { + case tpe: ThisType => This(tpe.cls).withSpan(tree.span) + case _ => tree + } case tree @ Select(qual, name) => if tree.symbol.is(Inline) then ctx.compilationUnit.needsInlining = true - if (name.isTypeName) { + if name.isTypeName then + checkNotPackage(tree) Checking.checkRealizable(qual.tpe, qual.srcPos) withMode(Mode.Type)(super.transform(tree)) - } else checkNoConstructorProxy(tree) transformSelect(tree, Nil) diff --git a/tests/neg/i12432.scala b/tests/neg/i12432.scala new file mode 100644 index 000000000000..ee7a06c44ea9 --- /dev/null +++ b/tests/neg/i12432.scala @@ -0,0 +1,4 @@ +package dotty.tools.dotc.typer + +class i1 ( i1 : annotation ) // error +class i2 ( a : scala.annotation ) // error \ No newline at end of file From 02a8b70ddc6914fd5a8dae183d2fbce8e3d5c94f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 23 May 2021 17:41:08 +0200 Subject: [PATCH 2/2] Address review comments --- compiler/src/dotty/tools/dotc/ast/Trees.scala | 5 ++++- .../src/dotty/tools/dotc/transform/PostTyper.scala | 11 +++++------ .../dotty/tools/dotc/transform/SyntheticMembers.scala | 2 +- tests/neg/i12432.scala | 6 +++--- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index f65154984f50..daa1754f7883 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -11,6 +11,7 @@ import printing.Printer import printing.Texts.Text import util.{Stats, Attachment, Property, SourceFile, NoSource, SrcPos, SourcePosition} import config.Config +import config.Printers.overload import annotation.internal.sharable import annotation.unchecked.uncheckedVariance import annotation.constructorOnly @@ -1729,7 +1730,9 @@ object Trees { val typer = ctx.typer val proto = FunProto(args, expectedType) val denot = receiver.tpe.member(method) - assert(denot.exists, i"no member $receiver . $method, members = ${receiver.tpe.decls}") + if !denot.exists then + overload.println(i"members = ${receiver.tpe.decls}") + report.error(i"no member $receiver . $method", receiver.srcPos) val selected = if (denot.isOverloaded) { def typeParamCount(tp: Type) = tp.widen match { diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 17e54139d11c..3c6217cf5171 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -7,6 +7,7 @@ import core._ import dotty.tools.dotc.typer.Checking import dotty.tools.dotc.typer.Inliner import dotty.tools.dotc.typer.VarianceChecker +import typer.ErrorReporting.errorTree import Types._, Contexts._, Names._, Flags._, DenotTransformers._, Phases._ import SymDenotations._, StdNames._, Annotations._, Trees._, Scopes._ import Decorators._ @@ -263,9 +264,9 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case Select(qual, _) => check(qual) // simple select _n case Apply(TypeApply(Select(qual, _), _), _) => check(qual) // generic select .apply[T](n) - def checkNotPackage(tree: Tree)(using Context): Unit = - if tree.symbol.is(Package) then - report.error(i"${tree.symbol} cannot be used as a type", tree.srcPos) + def checkNotPackage(tree: Tree)(using Context): Tree = + if !tree.symbol.is(Package) then tree + else errorTree(tree, i"${tree.symbol} cannot be used as a type") override def transform(tree: Tree)(using Context): Tree = try tree match { @@ -280,7 +281,6 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case tree: Ident => if tree.isType then checkNotPackage(tree) - tree else if tree.symbol.is(Inline) && !Inliner.inInlineMethod then ctx.compilationUnit.needsInlining = true @@ -293,9 +293,8 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase if tree.symbol.is(Inline) then ctx.compilationUnit.needsInlining = true if name.isTypeName then - checkNotPackage(tree) Checking.checkRealizable(qual.tpe, qual.srcPos) - withMode(Mode.Type)(super.transform(tree)) + withMode(Mode.Type)(super.transform(checkNotPackage(tree))) else checkNoConstructorProxy(tree) transformSelect(tree, Nil) diff --git a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala index 7634de643333..32256e43d242 100644 --- a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala +++ b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala @@ -262,7 +262,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) { // compare primitive fields first, slow equality checks of non-primitive fields can be skipped when primitives differ val sortedAccessors = accessors.sortBy(accessor => if (accessor.info.typeSymbol.isPrimitiveValueClass) 0 else 1) val comparisons = sortedAccessors.map { accessor => - This(clazz).select(accessor).equal(ref(thatAsClazz).select(accessor)) } + This(clazz).withSpan(ctx.owner.span.focus).select(accessor).equal(ref(thatAsClazz).select(accessor)) } var rhs = // this.x == this$0.x && this.y == x$0.y && that.canEqual(this) if comparisons.isEmpty then Literal(Constant(true)) else comparisons.reduceLeft(_ and _) val canEqualMeth = existingDef(defn.Product_canEqual, clazz) diff --git a/tests/neg/i12432.scala b/tests/neg/i12432.scala index ee7a06c44ea9..54f8dcf79c84 100644 --- a/tests/neg/i12432.scala +++ b/tests/neg/i12432.scala @@ -1,4 +1,4 @@ -package dotty.tools.dotc.typer -class i1 ( i1 : annotation ) // error -class i2 ( a : scala.annotation ) // error \ No newline at end of file +case class i1 ( i1 : annotation ) // error // error +class i2 ( a : scala.annotation ) // error +