Skip to content

Check import selectors at Typer #15477

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/core/TypeErrors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ class MissingType(pre: Type, name: Name) extends TypeError {
}
}

class RecursionOverflow(val op: String, details: => String, val previous: Throwable, val weight: Int) extends TypeError {
class RecursionOverflow(val op: String, details: => String, val previous: Throwable, val weight: Int)
extends TypeError {

def explanation: String = s"$op $details"

Expand Down
15 changes: 0 additions & 15 deletions compiler/src/dotty/tools/dotc/transform/PostTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -430,21 +430,6 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
case tpe => tpe
}
)
case Import(expr, selectors) =>
val exprTpe = expr.tpe
val seen = mutable.Set.empty[Name]

def checkIdent(sel: untpd.ImportSelector): Unit =
if !exprTpe.member(sel.name).exists
&& !exprTpe.member(sel.name.toTypeName).exists then
report.error(NotAMember(exprTpe, sel.name, "value"), sel.imported.srcPos)
if seen.contains(sel.name) then
report.error(ImportRenamedTwice(sel.imported), sel.imported.srcPos)
seen += sel.name

for sel <- selectors do
if !sel.isWildcard then checkIdent(sel)
super.transform(tree)
case Typed(Ident(nme.WILDCARD), _) =>
withMode(Mode.Pattern)(super.transform(tree))
// The added mode signals that bounds in a pattern need not
Expand Down
22 changes: 22 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1429,6 +1429,27 @@ trait Checking {
em"""Implementation restriction: cannot generate CanThrow capability for this kind of catch.
|CanThrow capabilities can only be generated $req.""",
pat.srcPos)

/** (1) Check that every named import selector refers to a type or value member of the
* qualifier type.
* (2) Check that no import selector is renamed more than once.
*/
def checkImportSelectors(qualType: Type, selectors: List[untpd.ImportSelector])(using Context): Unit =
val seen = mutable.Set.empty[Name]

def checkIdent(sel: untpd.ImportSelector): Unit =
if sel.name != nme.ERROR
&& !qualType.member(sel.name).exists
&& !qualType.member(sel.name.toTypeName).exists
then
report.error(NotAMember(qualType, sel.name, "value"), sel.imported.srcPos)
if seen.contains(sel.name) then
report.error(ImportRenamedTwice(sel.imported), sel.imported.srcPos)
seen += sel.name

for sel <- selectors do
if !sel.isWildcard then checkIdent(sel)
end checkImportSelectors
}

trait ReChecking extends Checking {
Expand Down Expand Up @@ -1466,4 +1487,5 @@ trait NoChecking extends ReChecking {
override def checkMembersOK(tp: Type, pos: SrcPos)(using Context): Type = tp
override def checkInInlineContext(what: String, pos: SrcPos)(using Context): Unit = ()
override def checkValidInfix(tree: untpd.InfixOp, meth: Symbol)(using Context): Unit = ()
override def checkImportSelectors(qualType: Type, selectors: List[untpd.ImportSelector])(using Context): Unit = ()
}
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2606,6 +2606,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
val expr1 = typedImportQualifier(imp, typedExpr(_, _)(using ctx.withOwner(sym)))
checkLegalImportPath(expr1)
val selectors1 = typedSelectors(imp.selectors)
checkImportSelectors(expr1.tpe, selectors1)
assignType(cpy.Import(imp)(expr1, selectors1), sym)

def typedExport(exp: untpd.Export)(using Context): Tree =
Expand Down
4 changes: 4 additions & 0 deletions tests/neg-custom-args/jdk-9-app.check
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
-- [E008] Not Found Error: tests/neg-custom-args/jdk-9-app.scala:1:17 --------------------------------------------------
1 |import java.lang.ProcessHandle // error: not a member
| ^^^^^^^^^^^^^
| value ProcessHandle is not a member of java.lang
-- [E006] Not Found Error: tests/neg-custom-args/jdk-9-app.scala:4:10 --------------------------------------------------
4 | println(ProcessHandle.current().pid()) // error: not found
| ^^^^^^^^^^^^^
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/jdk-9-app.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import java.lang.ProcessHandle
import java.lang.ProcessHandle // error: not a member

object Jdk9App extends App {
println(ProcessHandle.current().pid()) // error: not found
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/deriving.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import reflect.Generic
import reflect.Generic // error: Generic is not a member of reflect

sealed trait A derives Generic // error: cannot take shape, it has anonymous or inaccessible subclasses

Expand Down
6 changes: 6 additions & 0 deletions tests/neg/i15468.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
object Test {
val s = ""
import s.{length => x, size => y} // error: size is not a member of s
locally(x) // ok
locally(size) // error: Not found: y
}
2 changes: 1 addition & 1 deletion tests/neg/i6056.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
object i0{
import i0.i0 // error
import i0.i0 // error // error
def i0={
import _ // error
import // error
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/implicitDefs.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package test

import Predef.{any2stringadd as _, StringAdd as _, *}
import Predef.{any2stringadd as _, *}

object implicitDefs {

Expand Down
2 changes: 1 addition & 1 deletion tests/neg/language-import.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ object a:
import l.noAutoTupling // error
import l.experimental.genericNumberLiterals // error
val scala = c
import scala.language.noAutoTupling // error
import scala.language.noAutoTupling // error // error
val language = b
import language.experimental.genericNumberLiterals // error

Expand Down
2 changes: 1 addition & 1 deletion tests/neg/parser-stability-23.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
object i0 {
import Ordering.{ implicitly as } (true: Boolean) match { case _: i1 as true } // error // error
import Ordering.{ implicitly as } (true: Boolean) match { case _: i1 as true } // error // error // error
}
2 changes: 1 addition & 1 deletion tests/neg/rootImplicits.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package test

import Predef.{any2stringadd as _, StringAdd as _, *}
import Predef.{any2stringadd as _, *}

object rootImplicits {

Expand Down