Skip to content

Commit fab7147

Browse files
committed
Use experimental language import to enable the new behavior
1 parent bc36acb commit fab7147

File tree

12 files changed

+96
-23
lines changed

12 files changed

+96
-23
lines changed

compiler/src/dotty/tools/dotc/config/Feature.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ object Feature:
3333
val pureFunctions = experimental("pureFunctions")
3434
val captureChecking = experimental("captureChecking")
3535
val into = experimental("into")
36+
val avoidLoopingGivens = experimental("avoidLoopingGivens")
3637

3738
val globalOnlyImports: Set[TermName] = Set(pureFunctions, captureChecking)
3839

compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ object Scala3:
7777
type SemanticSymbol = Symbol | FakeSymbol
7878

7979
given SemanticSymbolOps : AnyRef with
80+
import SymbolOps.*
81+
import StringOps.*
82+
8083
extension (sym: SemanticSymbol)
8184
def name(using Context): Name = sym match
8285
case s: Symbol => s.name

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

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,19 +1589,40 @@ trait Implicits:
15891589

15901590
val eligible = if contextual then preEligible.filterNot(comesTooLate) else preEligible
15911591

1592-
def checkResolutionChange(result: SearchResult) = result match
1593-
case result: SearchSuccess
1594-
if (eligible ne preEligible) && !sourceVersion.isAtLeast(SourceVersion.`future`) =>
1595-
searchImplicit(preEligible.diff(eligible), contextual) match
1596-
case prevResult: SearchSuccess =>
1597-
report.error(
1598-
em"""Warning: result of implicit search for $pt will change.
1599-
|current result: ${prevResult.ref.symbol.showLocated}
1600-
|result with -source future: ${result.ref.symbol.showLocated}""",
1601-
srcPos
1602-
)
1603-
case _ =>
1604-
case _ =>
1592+
def checkResolutionChange(result: SearchResult) =
1593+
if (eligible ne preEligible)
1594+
&& !Feature.enabled(Feature.avoidLoopingGivens)
1595+
then searchImplicit(preEligible.diff(eligible), contextual) match
1596+
case prevResult: SearchSuccess =>
1597+
def remedy = pt match
1598+
case _: SelectionProto =>
1599+
"conversion,\n - use an import to get extension method into scope"
1600+
case _: ViewProto =>
1601+
"conversion"
1602+
case _ =>
1603+
"argument"
1604+
1605+
def showResult(r: SearchResult) = r match
1606+
case r: SearchSuccess => ctx.printer.toTextRef(r.ref).show
1607+
case r => r.show
1608+
1609+
result match
1610+
case result: SearchSuccess if prevResult.ref frozen_=:= result.ref =>
1611+
// OK
1612+
case _ =>
1613+
report.error(
1614+
em"""Warning: result of implicit search for $pt will change.
1615+
|Current result ${showResult(prevResult)} will be no longer eligible
1616+
| because it is not defined before the search position.
1617+
|Result with new rules: ${showResult(result)}.
1618+
|To opt into the new rules, use the `avoidLoopingGivens` language import,
1619+
|
1620+
|To fix the problem you could try one of the following:
1621+
| - rearrange definitions,
1622+
| - use an explicit $remedy.""",
1623+
srcPos)
1624+
case _ =>
1625+
end checkResolutionChange
16051626

16061627
searchImplicit(eligible, contextual) match
16071628
case result: SearchSuccess =>

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,6 +1781,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
17811781
end TypeRepr
17821782

17831783
given TypeReprMethods: TypeReprMethods with
1784+
import SymbolMethods.*
1785+
17841786
extension (self: TypeRepr)
17851787

17861788
def show(using printer: Printer[TypeRepr]): String = printer.show(self)
@@ -2608,6 +2610,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
26082610
end Symbol
26092611

26102612
given SymbolMethods: SymbolMethods with
2613+
import FlagsMethods.*
2614+
26112615
extension (self: Symbol)
26122616
def owner: Symbol = self.denot.owner
26132617
def maybeOwner: Symbol = self.denot.maybeOwner

library/src/scala/runtime/stdLibPatches/language.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,15 @@ object language:
9191
@compileTimeOnly("`into` can only be used at compile time in import statements")
9292
object into
9393

94+
/** Experimental support for new given resolution rules that avoid looping
95+
* givens. By the new rules, a given may not implicitly use itself or givens
96+
* defined after it.
97+
*
98+
* @see [[https://dotty.epfl.ch/docs/reference/experimental/avoid-looping-givens]]
99+
*/
100+
@compileTimeOnly("`avoidLoopingGivens` can only be used at compile time in import statements")
101+
object avoidLoopingGivens
102+
94103
/** Was needed to add support for relaxed imports of extension methods.
95104
* The language import is no longer needed as this is now a standard feature since SIP was accepted.
96105
* @see [[http://dotty.epfl.ch/docs/reference/contextual/extension-methods]]

tests/neg/i15474.check

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
-- Error: tests/neg/i15474.scala:16:56 ---------------------------------------------------------------------------------
22
16 | given Ordering[Price] = summon[Ordering[BigDecimal]] // error
33
| ^
4-
| Warning: result of implicit search for Ordering[BigDecimal] will change.
5-
| current result: given instance given_Ordering_Price in object Price
6-
| result with -source future: object BigDecimal in object Ordering
4+
| Warning: result of implicit search for Ordering[BigDecimal] will change.
5+
| Current result Prices.Price.given_Ordering_Price will be no longer eligible
6+
| because it is not defined before the search position.
7+
| Result with new rules: scala.math.Ordering.BigDecimal.
8+
| To opt into the new rules, use the `avoidLoopingGivens` language import,
9+
|
10+
| To fix the problem you could try one of the following:
11+
| - rearrange definitions,
12+
| - use an explicit argument.

tests/neg/i6716.check

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,11 @@
22
12 | given Monad[Bar] = summon[Monad[Foo]] // error
33
| ^
44
| Warning: result of implicit search for Monad[Foo] will change.
5-
| current result: given instance given_Monad_Bar in object Bar
6-
| result with -source future: object given_Monad_Foo in object Foo
5+
| Current result Bar.given_Monad_Bar will be no longer eligible
6+
| because it is not defined before the search position.
7+
| Result with new rules: Foo.given_Monad_Foo.
8+
| To opt into the new rules, use the `avoidLoopingGivens` language import,
9+
|
10+
| To fix the problem you could try one of the following:
11+
| - rearrange definitions,
12+
| - use an explicit argument.

tests/neg/i7294-a.check

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
-- Error: tests/neg/i7294-a.scala:6:10 ---------------------------------------------------------------------------------
2+
6 | case x: T => x.g(10) // error // error
3+
| ^
4+
| Warning: result of implicit search for scala.reflect.TypeTest[Nothing, T] will change.
5+
| Current result foo.i7294-a$package.f will be no longer eligible
6+
| because it is not defined before the search position.
7+
| Result with new rules: No Matching Implicit.
8+
| To opt into the new rules, use the `avoidLoopingGivens` language import,
9+
|
10+
| To fix the problem you could try one of the following:
11+
| - rearrange definitions,
12+
| - use an explicit argument.
13+
|
14+
| where: T is a type in given instance f with bounds <: foo.Foo
15+
-- [E007] Type Mismatch Error: tests/neg/i7294-a.scala:6:15 ------------------------------------------------------------
16+
6 | case x: T => x.g(10) // error // error
17+
| ^
18+
| Found: (x : Nothing)
19+
| Required: ?{ g: ? }
20+
| Note that implicit conversions were not tried because the result of an implicit conversion
21+
| must be more specific than ?{ g: [applied to (10) returning T] }
22+
|
23+
| longer explanation available when compiling with `-explain`

tests/neg/i7294-a.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package foo
33
trait Foo { def g(x: Int): Any }
44

55
inline given f[T <: Foo]: T = ??? match {
6-
case x: T => x.g(10) // error
6+
case x: T => x.g(10) // error // error
77
}
88

99
@main def Test = f

tests/neg/i7294-b.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package foo
33
trait Foo { def g(x: Any): Any }
44

55
inline given f[T <: Foo]: T = ??? match {
6-
case x: T => x.g(10) // error
6+
case x: T => x.g(10) // error // error
77
}
88

99
@main def Test = f

tests/pos/i15474.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//> using options -Xfatal-warnings
22
import scala.language.implicitConversions
3-
import language.future
3+
import scala.language.experimental.avoidLoopingGivens
44

55
object Test1:
66
given c: Conversion[ String, Int ] with

tests/run/i6716.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//> using options -Xfatal-warnings
22

3-
import language.future
3+
import scala.language.experimental.avoidLoopingGivens
44

55
trait Monad[T]:
66
def id: String
@@ -11,7 +11,7 @@ object Foo {
1111

1212
opaque type Bar = Foo
1313
object Bar {
14-
given Monad[Bar] = summon[Monad[Foo]] // error
14+
given Monad[Bar] = summon[Monad[Foo]] // was error fixed by avoidLoopingGivens
1515
}
1616

1717
object Test extends App {

0 commit comments

Comments
 (0)