diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index ad07b0ebd7a5..7303124b0cd4 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -18,6 +18,7 @@ import ErrorReporting.* import util.SourceFile import TypeComparer.necessarySubType import dotty.tools.dotc.core.Flags.Transparent +import dotty.tools.dotc.config.{ Feature, SourceVersion } import scala.annotation.internal.sharable @@ -113,9 +114,22 @@ object ProtoTypes { * achieved by replacing expected type parameters with wildcards. */ def constrainResult(meth: Symbol, mt: Type, pt: Type)(using Context): Boolean = - if (Inlines.isInlineable(meth) && meth.is(Transparent)) { - constrainResult(mt, wildApprox(pt)) - true + if (Inlines.isInlineable(meth)) { + // Stricter behaviour in 3.4+: do not apply `wildApprox` to non-transparent inlines + if (Feature.sourceVersion.isAtLeast(SourceVersion.future)) { + if (meth.is(Transparent)) { + constrainResult(mt, wildApprox(pt)) + // do not constrain the result type of transparent inline methods + true + } else { + constrainResult(mt, pt) + } + } else { + // Best-effort to fix https://github.com/lampepfl/dotty/issues/9685 in the 3.3.x series + // while preserving source compatibility as much as possible + val methodMatchedType = constrainResult(mt, wildApprox(pt)) + meth.is(Transparent) || methodMatchedType + } } else constrainResult(mt, pt) } diff --git a/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala b/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala index 2a665c478932..2a25cde34c8b 100644 --- a/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala @@ -109,6 +109,7 @@ class BootstrappedOnlyCompilationTests { implicit val testGroup: TestGroup = TestGroup("compileNegWithCompiler") aggregateTests( compileFilesInDir("tests/neg-macros", defaultOptions.and("-Xcheck-macros")), + compileFilesInDir("tests/neg-inlines-strict", defaultOptions.and("-source", "future")), compileFile("tests/pos-macros/i9570.scala", defaultOptions.and("-Xfatal-warnings")), compileFile("tests/pos-macros/macro-deprecation.scala", defaultOptions.and("-Xfatal-warnings", "-deprecation")), compileFile("tests/pos-macros/macro-experimental.scala", defaultOptions.and("-Yno-experimental")), diff --git a/tests/neg-inlines-strict/i9685bis.check b/tests/neg-inlines-strict/i9685bis.check new file mode 100644 index 000000000000..45e7f85aa30d --- /dev/null +++ b/tests/neg-inlines-strict/i9685bis.check @@ -0,0 +1,9 @@ +-- [E008] Not Found Error: tests/neg-macros/i9685bis.scala:23:4 -------------------------------------------------------- +23 | 1.asdf // error + | ^^^^^^ + | value asdf is not a member of Int, but could be made available as an extension method. + | + | The following import might make progress towards fixing the problem: + | + | import foo.Baz.toBaz + | diff --git a/tests/neg-inlines-strict/i9685bis.scala b/tests/neg-inlines-strict/i9685bis.scala new file mode 100644 index 000000000000..0023d4d719b4 --- /dev/null +++ b/tests/neg-inlines-strict/i9685bis.scala @@ -0,0 +1,23 @@ +package foo + +import scala.language.implicitConversions + +class Foo + +object Foo: + + inline implicit def toFoo(x: Int): Foo = Foo() + +class Bar + +object Bar: + inline given Conversion[Int, Bar] with + def apply(x: Int): Bar = Bar() + +class Baz + +object Baz: + transparent inline implicit def toBaz(x: Int): Baz = Baz() + +object Usage: + 1.asdf // error diff --git a/tests/pos-macros/i18123.scala b/tests/pos-macros/i18123.scala new file mode 100644 index 000000000000..714850004d2c --- /dev/null +++ b/tests/pos-macros/i18123.scala @@ -0,0 +1,25 @@ +// may not compile anymore in Scala 3.4+ +package pkg + +trait P[+T] + +extension [T](inline parse0: P[T]) + inline def | [V >: T](inline other: P[V]): P[V] = ??? + +extension [T](inline parse0: => P[T]) + inline def rep[V](inline min: Int = 0)(using repeater: Implicits.Repeater[T, V]): P[V] = ??? + +object Implicits: + trait Repeater[-T, R] + object Repeater: + implicit def GenericRepeaterImplicit[T]: Repeater[T, Seq[T]] = ??? + +sealed trait RegexTree +abstract class Node extends RegexTree +class CharClassIntersection() extends Node + +def classItem: P[RegexTree] = ??? +def charClassIntersection: P[CharClassIntersection] = ??? + +def x = + (charClassIntersection.rep() | classItem.rep())