From 01a51c358c43b640e8a537313feaf0cd56a394df Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 16 Oct 2024 09:07:21 -0700 Subject: [PATCH 1/3] Avoid highlighting Java source --- compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index 45caf480f65e..7fddfc8d6ed0 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -62,7 +62,7 @@ trait MessageRendering { } val syntax = - if (ctx.settings.color.value != "never") + if (ctx.settings.color.value != "never" && !ctx.isJava) SyntaxHighlighting.highlight(new String(pos.linesSlice)).toCharArray else pos.linesSlice val lines = linesFrom(syntax) From 004c4a8945ee4b8a6596286616806db293db381c Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 16 Oct 2024 11:19:56 -0700 Subject: [PATCH 2/3] Java package must be rooted --- .../dotty/tools/dotc/typer/TypeAssigner.scala | 4 +-- .../src/dotty/tools/dotc/typer/Typer.scala | 25 +++++++++++++------ tests/pos/t10350/Bar.scala | 6 +++++ tests/pos/t10350/Baz.java | 5 ++++ tests/pos/t10350/Foo.java | 14 +++++++++++ tests/pos/t11788/Bar.scala | 3 +++ tests/pos/t11788/Foo.java | 8 ++++++ tests/pos/t11788b/Bar.scala | 3 +++ tests/pos/t11788b/Foo.java | 8 ++++++ tests/pos/t11788b/java.java | 7 ++++++ 10 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 tests/pos/t10350/Bar.scala create mode 100644 tests/pos/t10350/Baz.java create mode 100644 tests/pos/t10350/Foo.java create mode 100644 tests/pos/t11788/Bar.scala create mode 100644 tests/pos/t11788/Foo.java create mode 100644 tests/pos/t11788b/Bar.scala create mode 100644 tests/pos/t11788b/Foo.java create mode 100644 tests/pos/t11788b/java.java diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 8448017cbada..28af86344621 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -125,8 +125,8 @@ trait TypeAssigner { /** The type of the selection `tree`, where `qual1` is the typed qualifier part. */ def selectionType(tree: untpd.RefTree, qual1: Tree)(using Context): Type = - val qualType0 = qual1.tpe.widenIfUnstable val qualType = + val qualType0 = qual1.tpe.widenIfUnstable if !qualType0.hasSimpleKind && tree.name != nme.CONSTRUCTOR then // constructors are selected on type constructor, type arguments are passed afterwards errorType(em"$qualType0 takes type parameters", qual1.srcPos) @@ -199,7 +199,7 @@ trait TypeAssigner { /** Type assignment method. Each method takes as parameters * - an untpd.Tree to which it assigns a type, - * - typed child trees it needs to access to cpmpute that type, + * - typed child trees it needs to access to compute that type, * - any further information it needs to access to compute that type. */ def assignType(tree: untpd.Ident, tp: Type)(using Context): Ident = diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index fd35471da07e..2eb63acf6bbe 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1008,13 +1008,24 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer typedSelectWithAdapt(tree, pt, qual).withSpan(tree.span).computeNullable() def javaSelection(qual: Tree)(using Context) = - val tree1 = assignType(cpy.Select(tree)(qual, tree.name), qual) - tree1.tpe match - case moduleRef: TypeRef if moduleRef.symbol.is(ModuleClass, butNot = JavaDefined) => - // handle unmangling of module names (Foo$ -> Foo[ModuleClass]) - cpy.Select(tree)(qual, tree.name.unmangleClassName).withType(moduleRef) - case _ => - tree1 + qual match + case id @ Ident(name) if id.symbol.is(Package) && !id.symbol.owner.isRoot => + def nextPackage(last: Symbol)(using Context): Type = + val startAt = ctx.outersIterator.dropWhile(_.owner != last.owner).drop(1).next() + val next = findRef(name, WildcardType, required = Package, EmptyFlags, qual.srcPos)(using startAt) + if next.exists && !next.typeSymbol.owner.isRoot then nextPackage(next.typeSymbol) + else next + val next = nextPackage(id.symbol) + val qual1 = if next.exists then assignType(cpy.Ident(id)(tree.name), next) else qual + assignType(cpy.Select(tree)(qual1, tree.name), qual1) + case _ => + val tree1 = assignType(cpy.Select(tree)(qual, tree.name), qual) + tree1.tpe match + case moduleRef: TypeRef if moduleRef.symbol.is(ModuleClass, butNot = JavaDefined) => + // handle unmangling of module names (Foo$ -> Foo[ModuleClass]) + cpy.Select(tree)(qual, tree.name.unmangleClassName).withType(moduleRef) + case _ => + tree1 def tryJavaSelectOnType(using Context): Tree = tree.qualifier match { case sel @ Select(qual, name) => diff --git a/tests/pos/t10350/Bar.scala b/tests/pos/t10350/Bar.scala new file mode 100644 index 000000000000..509d5af2b686 --- /dev/null +++ b/tests/pos/t10350/Bar.scala @@ -0,0 +1,6 @@ + +package bar + +object Bar { + def xxx(s: String): foo.Foo = foo.Foo.create(s) +} diff --git a/tests/pos/t10350/Baz.java b/tests/pos/t10350/Baz.java new file mode 100644 index 000000000000..c11c3875c3cb --- /dev/null +++ b/tests/pos/t10350/Baz.java @@ -0,0 +1,5 @@ + +package foo.java; + +interface Baz { +} diff --git a/tests/pos/t10350/Foo.java b/tests/pos/t10350/Foo.java new file mode 100644 index 000000000000..ea4bba7643e7 --- /dev/null +++ b/tests/pos/t10350/Foo.java @@ -0,0 +1,14 @@ + +package foo; + +public interface Foo { + static Foo create(java.lang.String v) { + return null; + } +} + +/* +5 | static Foo create(java.lang.String v) { + | ^^^^^^^^^ + | value lang is not a member of foo.java + */ diff --git a/tests/pos/t11788/Bar.scala b/tests/pos/t11788/Bar.scala new file mode 100644 index 000000000000..01c1838abe21 --- /dev/null +++ b/tests/pos/t11788/Bar.scala @@ -0,0 +1,3 @@ +object Bar extends App { + println(new Foo().test()) +} diff --git a/tests/pos/t11788/Foo.java b/tests/pos/t11788/Foo.java new file mode 100644 index 000000000000..ed0dc48a0b33 --- /dev/null +++ b/tests/pos/t11788/Foo.java @@ -0,0 +1,8 @@ +public class Foo { + private String java; + + public java.lang.Integer test() { + //return Integer.valueOf(42); + throw null; + } +} diff --git a/tests/pos/t11788b/Bar.scala b/tests/pos/t11788b/Bar.scala new file mode 100644 index 000000000000..01c1838abe21 --- /dev/null +++ b/tests/pos/t11788b/Bar.scala @@ -0,0 +1,3 @@ +object Bar extends App { + println(new Foo().test()) +} diff --git a/tests/pos/t11788b/Foo.java b/tests/pos/t11788b/Foo.java new file mode 100644 index 000000000000..ed0dc48a0b33 --- /dev/null +++ b/tests/pos/t11788b/Foo.java @@ -0,0 +1,8 @@ +public class Foo { + private String java; + + public java.lang.Integer test() { + //return Integer.valueOf(42); + throw null; + } +} diff --git a/tests/pos/t11788b/java.java b/tests/pos/t11788b/java.java new file mode 100644 index 000000000000..2301bc90a177 --- /dev/null +++ b/tests/pos/t11788b/java.java @@ -0,0 +1,7 @@ + +public class java { + public static class lang { + public static class Integer { + } + } +} From d0f05bad8156ca5b3673fb1f692a7ab2b3e413d6 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 17 Oct 2024 10:54:29 -0700 Subject: [PATCH 3/3] Root of Java select must be class or rooted package Packaging avoids TreeChecker snafu in test --- .../src/dotty/tools/dotc/typer/Typer.scala | 40 ++++++++++++------- tests/pos/t11788/Bar.scala | 2 + tests/pos/t11788/Foo.java | 3 ++ tests/pos/t11788b/Bar.scala | 2 + tests/pos/t11788b/Foo.java | 2 + tests/pos/t11788b/java.java | 1 + tests/pos/t11788c/Bar.scala | 5 +++ tests/pos/t11788c/Foo.java | 10 +++++ tests/pos/t11788c/java.java | 10 +++++ 9 files changed, 60 insertions(+), 15 deletions(-) create mode 100644 tests/pos/t11788c/Bar.scala create mode 100644 tests/pos/t11788c/Foo.java create mode 100644 tests/pos/t11788c/java.java diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 2eb63acf6bbe..ebcd4bc014cb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1001,22 +1001,35 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer record("typedSelect") def typeSelectOnTerm(using Context): Tree = - val qual = typedExpr(tree.qualifier, shallowSelectionProto(tree.name, pt, this, tree.nameSpan)) if ctx.isJava then - javaSelection(qual) + // permitted selection depends on Java context (type or expression). + // we don't propagate (as a mode) whether a.b.m is a type name; OK since we only see type contexts. + // to allow correct selections, approximate by fallback for x.y: take x as class or (rooted) package. + def tryQualFallback(qual: untpd.Ident, name: Name)(using Context): Tree = + val qualTpe = + findRef(name.toTypeName, WildcardType, EmptyFlags, EmptyFlags, qual.srcPos) match + case tpe: NamedType if tpe.symbol.isClass => tpe + case _ => + val maybePackage = defn.RootPackage.info.member(name) + if maybePackage.exists then maybePackage.info else NoType + if qualTpe.exists then + javaSelection(assignType(cpy.Ident(qual)(name), qualTpe)) + else + errorTree(tree, em"no class or package to resolve `$name`") // just fail fallback + def tryQual(qual: untpd.Tree)(using Context): Tree = + javaSelection(typedExpr(qual, shallowSelectionProto(tree.name, pt, this, tree.nameSpan))) + tree.qualifier match + case qual @ Ident(name) => tryAlternatively(tryQual(qual))(tryQualFallback(qual, name)) + case qual => tryQual(qual) else + val qual = typedExpr(tree.qualifier, shallowSelectionProto(tree.name, pt, this, tree.nameSpan)) typedSelectWithAdapt(tree, pt, qual).withSpan(tree.span).computeNullable() def javaSelection(qual: Tree)(using Context) = qual match case id @ Ident(name) if id.symbol.is(Package) && !id.symbol.owner.isRoot => - def nextPackage(last: Symbol)(using Context): Type = - val startAt = ctx.outersIterator.dropWhile(_.owner != last.owner).drop(1).next() - val next = findRef(name, WildcardType, required = Package, EmptyFlags, qual.srcPos)(using startAt) - if next.exists && !next.typeSymbol.owner.isRoot then nextPackage(next.typeSymbol) - else next - val next = nextPackage(id.symbol) - val qual1 = if next.exists then assignType(cpy.Ident(id)(tree.name), next) else qual + val rooted = defn.RootPackage.info.member(name) + val qual1 = if rooted.exists then assignType(cpy.Ident(id)(name), rooted.info) else qual assignType(cpy.Select(tree)(qual1, tree.name), qual1) case _ => val tree1 = assignType(cpy.Select(tree)(qual, tree.name), qual) @@ -1042,17 +1055,14 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer errorTree(tree, em"cannot convert to type selection") // will never be printed due to fallback } - def selectWithFallback(fallBack: Context ?=> Tree) = - tryAlternatively(typeSelectOnTerm)(fallBack) - if (tree.qualifier.isType) { val qual1 = typedType(tree.qualifier, shallowSelectionProto(tree.name, pt, this, tree.nameSpan)) assignType(cpy.Select(tree)(qual1, tree.name), qual1) } else if (ctx.isJava && tree.name.isTypeName) - // SI-3120 Java uses the same syntax, A.B, to express selection from the - // value A and from the type A. We have to try both. - selectWithFallback(tryJavaSelectOnType) // !!! possibly exponential bcs of qualifier retyping + // scala/bug#3120 Java uses the same syntax, A.B, to express selection from the + // value A and from the type A. We have to try both. (possibly exponential bc of qualifier retyping) + tryAlternatively(typeSelectOnTerm)(tryJavaSelectOnType) else typeSelectOnTerm } diff --git a/tests/pos/t11788/Bar.scala b/tests/pos/t11788/Bar.scala index 01c1838abe21..f3d61e4f468f 100644 --- a/tests/pos/t11788/Bar.scala +++ b/tests/pos/t11788/Bar.scala @@ -1,3 +1,5 @@ +package p + object Bar extends App { println(new Foo().test()) } diff --git a/tests/pos/t11788/Foo.java b/tests/pos/t11788/Foo.java index ed0dc48a0b33..5b2224b6e00c 100644 --- a/tests/pos/t11788/Foo.java +++ b/tests/pos/t11788/Foo.java @@ -1,6 +1,9 @@ +package p; + public class Foo { private String java; + // java is the rooted package, not the field public java.lang.Integer test() { //return Integer.valueOf(42); throw null; diff --git a/tests/pos/t11788b/Bar.scala b/tests/pos/t11788b/Bar.scala index 01c1838abe21..f3d61e4f468f 100644 --- a/tests/pos/t11788b/Bar.scala +++ b/tests/pos/t11788b/Bar.scala @@ -1,3 +1,5 @@ +package p + object Bar extends App { println(new Foo().test()) } diff --git a/tests/pos/t11788b/Foo.java b/tests/pos/t11788b/Foo.java index ed0dc48a0b33..960085bd453f 100644 --- a/tests/pos/t11788b/Foo.java +++ b/tests/pos/t11788b/Foo.java @@ -1,3 +1,5 @@ +package p; + public class Foo { private String java; diff --git a/tests/pos/t11788b/java.java b/tests/pos/t11788b/java.java index 2301bc90a177..713e265b5e72 100644 --- a/tests/pos/t11788b/java.java +++ b/tests/pos/t11788b/java.java @@ -1,3 +1,4 @@ +package p; public class java { public static class lang { diff --git a/tests/pos/t11788c/Bar.scala b/tests/pos/t11788c/Bar.scala new file mode 100644 index 000000000000..f3d61e4f468f --- /dev/null +++ b/tests/pos/t11788c/Bar.scala @@ -0,0 +1,5 @@ +package p + +object Bar extends App { + println(new Foo().test()) +} diff --git a/tests/pos/t11788c/Foo.java b/tests/pos/t11788c/Foo.java new file mode 100644 index 000000000000..c244f1f13554 --- /dev/null +++ b/tests/pos/t11788c/Foo.java @@ -0,0 +1,10 @@ +package p; + +public class Foo { + private String java; + + // java is class in scope, not the term member or package + public java.lang.Integer.Inner test() { + throw null; + } +} diff --git a/tests/pos/t11788c/java.java b/tests/pos/t11788c/java.java new file mode 100644 index 000000000000..3b5ff8e11cd2 --- /dev/null +++ b/tests/pos/t11788c/java.java @@ -0,0 +1,10 @@ +package p; + +public class java { + public static class lang { + public static class Integer { + public static class Inner { + } + } + } +}