Skip to content

Commit d0f05ba

Browse files
committed
Root of Java select must be class or rooted package
Packaging avoids TreeChecker snafu in test
1 parent 004c4a8 commit d0f05ba

File tree

9 files changed

+60
-15
lines changed

9 files changed

+60
-15
lines changed

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

+25-15
Original file line numberDiff line numberDiff line change
@@ -1001,22 +1001,35 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
10011001
record("typedSelect")
10021002

10031003
def typeSelectOnTerm(using Context): Tree =
1004-
val qual = typedExpr(tree.qualifier, shallowSelectionProto(tree.name, pt, this, tree.nameSpan))
10051004
if ctx.isJava then
1006-
javaSelection(qual)
1005+
// permitted selection depends on Java context (type or expression).
1006+
// we don't propagate (as a mode) whether a.b.m is a type name; OK since we only see type contexts.
1007+
// to allow correct selections, approximate by fallback for x.y: take x as class or (rooted) package.
1008+
def tryQualFallback(qual: untpd.Ident, name: Name)(using Context): Tree =
1009+
val qualTpe =
1010+
findRef(name.toTypeName, WildcardType, EmptyFlags, EmptyFlags, qual.srcPos) match
1011+
case tpe: NamedType if tpe.symbol.isClass => tpe
1012+
case _ =>
1013+
val maybePackage = defn.RootPackage.info.member(name)
1014+
if maybePackage.exists then maybePackage.info else NoType
1015+
if qualTpe.exists then
1016+
javaSelection(assignType(cpy.Ident(qual)(name), qualTpe))
1017+
else
1018+
errorTree(tree, em"no class or package to resolve `$name`") // just fail fallback
1019+
def tryQual(qual: untpd.Tree)(using Context): Tree =
1020+
javaSelection(typedExpr(qual, shallowSelectionProto(tree.name, pt, this, tree.nameSpan)))
1021+
tree.qualifier match
1022+
case qual @ Ident(name) => tryAlternatively(tryQual(qual))(tryQualFallback(qual, name))
1023+
case qual => tryQual(qual)
10071024
else
1025+
val qual = typedExpr(tree.qualifier, shallowSelectionProto(tree.name, pt, this, tree.nameSpan))
10081026
typedSelectWithAdapt(tree, pt, qual).withSpan(tree.span).computeNullable()
10091027

10101028
def javaSelection(qual: Tree)(using Context) =
10111029
qual match
10121030
case id @ Ident(name) if id.symbol.is(Package) && !id.symbol.owner.isRoot =>
1013-
def nextPackage(last: Symbol)(using Context): Type =
1014-
val startAt = ctx.outersIterator.dropWhile(_.owner != last.owner).drop(1).next()
1015-
val next = findRef(name, WildcardType, required = Package, EmptyFlags, qual.srcPos)(using startAt)
1016-
if next.exists && !next.typeSymbol.owner.isRoot then nextPackage(next.typeSymbol)
1017-
else next
1018-
val next = nextPackage(id.symbol)
1019-
val qual1 = if next.exists then assignType(cpy.Ident(id)(tree.name), next) else qual
1031+
val rooted = defn.RootPackage.info.member(name)
1032+
val qual1 = if rooted.exists then assignType(cpy.Ident(id)(name), rooted.info) else qual
10201033
assignType(cpy.Select(tree)(qual1, tree.name), qual1)
10211034
case _ =>
10221035
val tree1 = assignType(cpy.Select(tree)(qual, tree.name), qual)
@@ -1042,17 +1055,14 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
10421055
errorTree(tree, em"cannot convert to type selection") // will never be printed due to fallback
10431056
}
10441057

1045-
def selectWithFallback(fallBack: Context ?=> Tree) =
1046-
tryAlternatively(typeSelectOnTerm)(fallBack)
1047-
10481058
if (tree.qualifier.isType) {
10491059
val qual1 = typedType(tree.qualifier, shallowSelectionProto(tree.name, pt, this, tree.nameSpan))
10501060
assignType(cpy.Select(tree)(qual1, tree.name), qual1)
10511061
}
10521062
else if (ctx.isJava && tree.name.isTypeName)
1053-
// SI-3120 Java uses the same syntax, A.B, to express selection from the
1054-
// value A and from the type A. We have to try both.
1055-
selectWithFallback(tryJavaSelectOnType) // !!! possibly exponential bcs of qualifier retyping
1063+
// scala/bug#3120 Java uses the same syntax, A.B, to express selection from the
1064+
// value A and from the type A. We have to try both. (possibly exponential bc of qualifier retyping)
1065+
tryAlternatively(typeSelectOnTerm)(tryJavaSelectOnType)
10561066
else
10571067
typeSelectOnTerm
10581068
}

tests/pos/t11788/Bar.scala

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
package p
2+
13
object Bar extends App {
24
println(new Foo().test())
35
}

tests/pos/t11788/Foo.java

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
package p;
2+
13
public class Foo {
24
private String java;
35

6+
// java is the rooted package, not the field
47
public java.lang.Integer test() {
58
//return Integer.valueOf(42);
69
throw null;

tests/pos/t11788b/Bar.scala

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
package p
2+
13
object Bar extends App {
24
println(new Foo().test())
35
}

tests/pos/t11788b/Foo.java

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
package p;
2+
13
public class Foo {
24
private String java;
35

tests/pos/t11788b/java.java

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
package p;
12

23
public class java {
34
public static class lang {

tests/pos/t11788c/Bar.scala

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package p
2+
3+
object Bar extends App {
4+
println(new Foo().test())
5+
}

tests/pos/t11788c/Foo.java

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

tests/pos/t11788c/java.java

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package p;
2+
3+
public class java {
4+
public static class lang {
5+
public static class Integer {
6+
public static class Inner {
7+
}
8+
}
9+
}
10+
}

0 commit comments

Comments
 (0)