Skip to content

Commit

Permalink
Root of Java select must be class or rooted package
Browse files Browse the repository at this point in the history
  • Loading branch information
som-snytt committed Oct 17, 2024
1 parent 7ee1709 commit f76979b
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 15 deletions.
41 changes: 26 additions & 15 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -986,22 +986,36 @@ 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)
def tryQual(qual: untpd.Tree)(using Context): Tree =
javaSelection(typedExpr(qual, shallowSelectionProto(tree.name, pt, this, tree.nameSpan)))
// 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 =
val maybeClass = findRef(name, WildcardType, EmptyFlags, EmptyFlags, qual.srcPos)
if maybeClass.exists then maybeClass
else
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
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).info
val qual1 = if rooted.exists then assignType(cpy.Ident(id)(name), rooted) else qual
assignType(cpy.Select(tree)(qual1, tree.name), qual1)
case _ =>
val tree1 = assignType(cpy.Select(tree)(qual, tree.name), qual)
Expand All @@ -1027,17 +1041,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
}
Expand Down
1 change: 1 addition & 0 deletions tests/pos/t11788/Foo.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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;
Expand Down
3 changes: 3 additions & 0 deletions tests/pos/t11788c/Bar.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object Bar extends App {
println(new Foo().test())
}
8 changes: 8 additions & 0 deletions tests/pos/t11788c/Foo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
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;
}
}
9 changes: 9 additions & 0 deletions tests/pos/t11788c/java.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

public class java {
public static class lang {
public static class Integer {
public static class Inner {
}
}
}
}

0 comments on commit f76979b

Please sign in to comment.