Skip to content

Commit f76979b

Browse files
committed
Root of Java select must be class or rooted package
1 parent 7ee1709 commit f76979b

File tree

5 files changed

+47
-15
lines changed

5 files changed

+47
-15
lines changed

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -986,22 +986,36 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
986986
record("typedSelect")
987987

988988
def typeSelectOnTerm(using Context): Tree =
989-
val qual = typedExpr(tree.qualifier, shallowSelectionProto(tree.name, pt, this, tree.nameSpan))
990989
if ctx.isJava then
991-
javaSelection(qual)
990+
def tryQual(qual: untpd.Tree)(using Context): Tree =
991+
javaSelection(typedExpr(qual, shallowSelectionProto(tree.name, pt, this, tree.nameSpan)))
992+
// permitted selection depends on Java context (type or expression).
993+
// we don't propagate (as a mode) whether a.b.m is a type name; OK since we only see type contexts.
994+
// to allow correct selections, approximate by fallback for x.y: take x as class or (rooted) package.
995+
def tryQualFallback(qual: untpd.Ident, name: Name)(using Context): Tree =
996+
val qualTpe =
997+
val maybeClass = findRef(name, WildcardType, EmptyFlags, EmptyFlags, qual.srcPos)
998+
if maybeClass.exists then maybeClass
999+
else
1000+
val maybePackage = defn.RootPackage.info.member(name)
1001+
if maybePackage.exists then maybePackage.info
1002+
else NoType
1003+
if qualTpe.exists then
1004+
javaSelection(assignType(cpy.Ident(qual)(name), qualTpe))
1005+
else
1006+
errorTree(tree, em"no class or package to resolve `$name`") // just fail fallback
1007+
tree.qualifier match
1008+
case qual @ Ident(name) => tryAlternatively(tryQual(qual))(tryQualFallback(qual, name))
1009+
case qual => tryQual(qual)
9921010
else
1011+
val qual = typedExpr(tree.qualifier, shallowSelectionProto(tree.name, pt, this, tree.nameSpan))
9931012
typedSelectWithAdapt(tree, pt, qual).withSpan(tree.span).computeNullable()
9941013

9951014
def javaSelection(qual: Tree)(using Context) =
9961015
qual match
9971016
case id @ Ident(name) if id.symbol.is(Package) && !id.symbol.owner.isRoot =>
998-
def nextPackage(last: Symbol)(using Context): Type =
999-
val startAt = ctx.outersIterator.dropWhile(_.owner != last.owner).drop(1).next()
1000-
val next = findRef(name, WildcardType, required = Package, EmptyFlags, qual.srcPos)(using startAt)
1001-
if next.exists && !next.typeSymbol.owner.isRoot then nextPackage(next.typeSymbol)
1002-
else next
1003-
val next = nextPackage(id.symbol)
1004-
val qual1 = if next.exists then assignType(cpy.Ident(id)(tree.name), next) else qual
1017+
val rooted = defn.RootPackage.info.member(name).info
1018+
val qual1 = if rooted.exists then assignType(cpy.Ident(id)(name), rooted) else qual
10051019
assignType(cpy.Select(tree)(qual1, tree.name), qual1)
10061020
case _ =>
10071021
val tree1 = assignType(cpy.Select(tree)(qual, tree.name), qual)
@@ -1027,17 +1041,14 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
10271041
errorTree(tree, em"cannot convert to type selection") // will never be printed due to fallback
10281042
}
10291043

1030-
def selectWithFallback(fallBack: Context ?=> Tree) =
1031-
tryAlternatively(typeSelectOnTerm)(fallBack)
1032-
10331044
if (tree.qualifier.isType) {
10341045
val qual1 = typedType(tree.qualifier, shallowSelectionProto(tree.name, pt, this, tree.nameSpan))
10351046
assignType(cpy.Select(tree)(qual1, tree.name), qual1)
10361047
}
10371048
else if (ctx.isJava && tree.name.isTypeName)
1038-
// SI-3120 Java uses the same syntax, A.B, to express selection from the
1039-
// value A and from the type A. We have to try both.
1040-
selectWithFallback(tryJavaSelectOnType) // !!! possibly exponential bcs of qualifier retyping
1049+
// scala/bug#3120 Java uses the same syntax, A.B, to express selection from the
1050+
// value A and from the type A. We have to try both. (possibly exponential bc of qualifier retyping)
1051+
tryAlternatively(typeSelectOnTerm)(tryJavaSelectOnType)
10411052
else
10421053
typeSelectOnTerm
10431054
}

tests/pos/t11788/Foo.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
public class Foo {
22
private String java;
33

4+
// java is the rooted package, not the field
45
public java.lang.Integer test() {
56
//return Integer.valueOf(42);
67
throw null;

tests/pos/t11788c/Bar.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Bar extends App {
2+
println(new Foo().test())
3+
}

tests/pos/t11788c/Foo.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
public class Foo {
2+
private String java;
3+
4+
// java is class in scope, not the term member or package
5+
public java.lang.Integer.Inner test() {
6+
throw null;
7+
}
8+
}

tests/pos/t11788c/java.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
public class java {
3+
public static class lang {
4+
public static class Integer {
5+
public static class Inner {
6+
}
7+
}
8+
}
9+
}

0 commit comments

Comments
 (0)