-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Backport "Avoid generating given definitions that loop" (#19477)
- Loading branch information
Showing
27 changed files
with
413 additions
and
53 deletions.
There are no files selected for viewing
Submodule specs2
updated
1 files
+6 −6 | matcher/shared/src/main/scala/org/specs2/matcher/describe/Diffable.scala |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
docs/_docs/reference/experimental/given-loop-prevention.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
--- | ||
layout: doc-page | ||
title: Given Loop Prevention | ||
redirectFrom: /docs/reference/other-new-features/into-modifier.html | ||
nightlyOf: https://docs.scala-lang.org/scala3/reference/experimental/into-modifier.html | ||
--- | ||
|
||
Implicit resolution now avoids generating recursive givens that can lead to an infinite loop at runtime. Here is an example: | ||
|
||
```scala | ||
object Prices { | ||
opaque type Price = BigDecimal | ||
|
||
object Price{ | ||
given Ordering[Price] = summon[Ordering[BigDecimal]] // was error, now avoided | ||
} | ||
} | ||
``` | ||
|
||
Previously, implicit resolution would resolve the `summon` to the given in `Price`, leading to an infinite loop (a warning was issued in that case). We now use the underlying given in `BigDecimal` instead. We achieve that by adding the following rule for implicit search: | ||
|
||
- When doing an implicit search while checking the implementation of a `given` definition `G` of the form | ||
``` | ||
given ... = .... | ||
``` | ||
discard all search results that lead back to `G` or to a given with the same owner as `G` that comes later in the source than `G`. | ||
The new behavior is enabled with the `experimental.givenLoopPrevention` language import. If no such import or setting is given, a warning is issued where the behavior would change under that import (for source version 3.4 and later). | ||
Old-style implicit definitions are unaffected by this change. | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
-- Error: tests/neg/i15474.scala:6:39 ---------------------------------------------------------------------------------- | ||
6 | given c: Conversion[ String, Int ] = _.toInt // error | ||
| ^ | ||
| Result of implicit search for ?{ toInt: ? } will change. | ||
| Current result Test2.c will be no longer eligible | ||
| because it is not defined before the search position. | ||
| Result with new rules: augmentString. | ||
| To opt into the new rules, compile with `-source future` or use | ||
| the `scala.language.future` language import. | ||
| | ||
| To fix the problem without the language import, you could try one of the following: | ||
| - use a `given ... with` clause as the enclosing given, | ||
| - rearrange definitions so that Test2.c comes earlier, | ||
| - use an explicit conversion, | ||
| - use an import to get extension method into scope. | ||
| This will be an error in Scala 3.5 and later. | ||
-- Error: tests/neg/i15474.scala:12:56 --------------------------------------------------------------------------------- | ||
12 | given Ordering[Price] = summon[Ordering[BigDecimal]] // error | ||
| ^ | ||
| Result of implicit search for Ordering[BigDecimal] will change. | ||
| Current result Prices.Price.given_Ordering_Price will be no longer eligible | ||
| because it is not defined before the search position. | ||
| Result with new rules: scala.math.Ordering.BigDecimal. | ||
| To opt into the new rules, compile with `-source future` or use | ||
| the `scala.language.future` language import. | ||
| | ||
| To fix the problem without the language import, you could try one of the following: | ||
| - use a `given ... with` clause as the enclosing given, | ||
| - rearrange definitions so that Prices.Price.given_Ordering_Price comes earlier, | ||
| - use an explicit argument. | ||
| This will be an error in Scala 3.5 and later. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
-- Error: tests/neg/i15474b.scala:7:40 --------------------------------------------------------------------------------- | ||
7 | def apply(from: String): Int = from.toInt // error: infinite loop in function body | ||
| ^^^^^^^^^^ | ||
| Infinite loop in function body | ||
| Test1.c.apply(from).toInt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
//> using options -Xfatal-warnings | ||
|
||
import scala.language.implicitConversions | ||
|
||
object Test1: | ||
given c: Conversion[ String, Int ] with | ||
def apply(from: String): Int = from.toInt // error: infinite loop in function body | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
-- Error: tests/neg/i6716.scala:12:39 ---------------------------------------------------------------------------------- | ||
12 | given Monad[Bar] = summon[Monad[Foo]] // error | ||
| ^ | ||
| Result of implicit search for Monad[Foo] will change. | ||
| Current result Bar.given_Monad_Bar will be no longer eligible | ||
| because it is not defined before the search position. | ||
| Result with new rules: Foo.given_Monad_Foo. | ||
| To opt into the new rules, compile with `-source future` or use | ||
| the `scala.language.future` language import. | ||
| | ||
| To fix the problem without the language import, you could try one of the following: | ||
| - use a `given ... with` clause as the enclosing given, | ||
| - rearrange definitions so that Bar.given_Monad_Bar comes earlier, | ||
| - use an explicit argument. | ||
| This will be an error in Scala 3.5 and later. |
Oops, something went wrong.