From ce77e475e0639551bafd699c0d5aad616f6919ed Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 2 Dec 2020 11:58:38 +0100 Subject: [PATCH] Fix #10295: Require import qualifiers to be idempotent The use case for contextual abstractions is still supported if the function returning an implicit parameter is declared `inline`. --- .../src/dotty/tools/dotc/typer/Checking.scala | 2 ++ tests/neg/i10295.scala | 4 +++ tests/pos/i10295.scala | 36 +++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 tests/neg/i10295.scala create mode 100644 tests/pos/i10295.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 90d007074c83..3820a766fc55 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -723,6 +723,8 @@ trait Checking { def checkLegalImportPath(path: Tree)(using Context): Unit = { checkStable(path.tpe, path.srcPos, "import prefix") if (!ctx.isAfterTyper) Checking.checkRealizable(path.tpe, path.srcPos) + if !isIdempotentExpr(path) then + report.error(em"import prefix is not a pure expression", path.srcPos) } /** Check that `tp` is a class type. diff --git a/tests/neg/i10295.scala b/tests/neg/i10295.scala new file mode 100644 index 000000000000..75c8da8a5c11 --- /dev/null +++ b/tests/neg/i10295.scala @@ -0,0 +1,4 @@ +def get: 1 = { println("hi"); 1 } +import get._ // error: import prefix is not a pure expression +val x = get.toLong + diff --git a/tests/pos/i10295.scala b/tests/pos/i10295.scala new file mode 100644 index 000000000000..8fc237e2e853 --- /dev/null +++ b/tests/pos/i10295.scala @@ -0,0 +1,36 @@ +trait M: + type X + object X: + def foo(): X = ??? + +inline def m(using m: M): m.type = m + +def doSomething(body: M ?=> Unit) = body(using new M{}) + + +def Test1 = + given M = new M{} + import m._ + val x: X = X.foo() + println(x) + +def Test2 = + + doSomething { + val x: m.X = m.X.foo() + println(x) + } + // or with an import + doSomething { + import m._ // Concise and clear import of the same stable path `m` + val x: X = X.foo() + println(x) + } + // without this feature we would need an extra line in each call site + doSomething { + // not ideal + val myM = m // or summon[M] + import myM._ + val x: X = X.foo() + println(x) + }