Skip to content

Commit 76ebf6a

Browse files
dwijnandtgodzik
authored andcommitted
Relax method signature matching under Mode.CheckBoundsOrSelfType
[Cherry-picked d64766f]
1 parent 558231f commit 76ebf6a

File tree

5 files changed

+405
-3
lines changed

5 files changed

+405
-3
lines changed

compiler/src/dotty/tools/dotc/core/CheckRealizable.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ class CheckRealizable(using Context) {
139139
/** `Realizable` if `tp` has good bounds, a `HasProblem...` instance
140140
* pointing to a bad bounds member otherwise. "Has good bounds" means:
141141
*
142-
* - all type members have good bounds (except for opaque helpers)
143-
* - all refinements of the underlying type have good bounds (except for opaque companions)
142+
* - all type members have good bounds
143+
* - all refinements of the underlying type have good bounds
144144
* - all base types are class types, and if their arguments are wildcards
145145
* they have good bounds.
146146
* - base types do not appear in multiple instances with different arguments.

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2005,11 +2005,16 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
20052005
// resort to reflection to invoke the member. And Java reflection needs to know exact
20062006
// erased parameter types. See neg/i12211.scala. Other reflection algorithms could
20072007
// conceivably dispatch without knowing precise parameter signatures. One can signal
2008-
// this by inheriting from the `scala.reflect.SignatureCanBeImprecise` marker trait,
2008+
// this by inheriting from the `scala.Selectable.WithoutPreciseParameterTypes` marker trait,
20092009
// in which case the signature test is elided.
2010+
// We also relax signature checking when checking bounds,
2011+
// for instance in tests/pos/i17222.izumi.min.scala
2012+
// the `go` method info as seen from `Foo` is `>: (in: Any): Unit <: (Nothing): Unit`
2013+
// So the parameter types conform but their signatures don't match.
20102014
def sigsOK(symInfo: Type, info2: Type) =
20112015
tp2.underlyingClassRef(refinementOK = true).member(name).exists
20122016
|| tp2.derivesFrom(defn.WithoutPreciseParameterTypesClass)
2017+
|| ctx.mode.is(Mode.CheckBoundsOrSelfType)
20132018
|| symInfo.isInstanceOf[MethodType]
20142019
&& symInfo.signature.consistentParams(info2.signature)
20152020

tests/pos/i17222.izumi.min.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Foo:
2+
type In
3+
type Bar = { def go(in: In): Unit }
4+
type False = false
5+
6+
class Test:
7+
def t1: Unit = valueOf[Foo#False]
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package izumi.reflect.dottyreflection
2+
3+
import scala.quoted.Quotes
4+
5+
trait InspectorBase extends ReflectionUtil {
6+
7+
val qctx: Quotes
8+
import qctx.reflect._
9+
10+
protected def shift: Int
11+
12+
// FIXME reimplement TrivialMacroLogger on Scala 3
13+
inline def debug: debug = valueOf[debug]
14+
final type debug = false
15+
16+
// println instead of report.info because report.info eats all the subsequent report.info's after first.
17+
inline final protected def logStart(inline s: String): Unit = {
18+
inline if (debug) println(" " * shift + currentPositionStr + s)
19+
}
20+
21+
inline final protected def log(inline s: String): Unit = {
22+
inline if (debug) println(" " * shift + currentPositionStr + " -> " + s)
23+
}
24+
25+
inline final protected def logTpeAttrs[T](inline typeRepr: TypeRepr): Unit = {
26+
inline if (debug) {
27+
val tree = TypeTree.of(using typeRepr.asType)
28+
val symbol = tree.symbol
29+
System
30+
.err.println(
31+
currentPositionStr + ": " +
32+
s"Attrs[${tree.show}]: type=${symbol.isType}, term=${symbol.isTerm}, packageDef=${symbol.isPackageDef}, classDef=${symbol.isClassDef}, typeDef=${symbol.isValDef}, defdef=${symbol.isDefDef}, bind=${symbol.isBind}, nosymbol=${symbol.isNoSymbol}"
33+
)
34+
}
35+
}
36+
37+
private def currentPositionStr: String = {
38+
val pos = qctx.reflect.Position.ofMacroExpansion
39+
s"${pos.sourceFile.name}:${pos.endLine}"
40+
}
41+
42+
}
43+
44+
object InspectorBase {
45+
46+
private[reflect] inline def ifDebug[A](inline f: => Unit): Unit = {
47+
inline if (valueOf[InspectorBase#debug]) {
48+
//[error] ^^^^^^^^^^^^^
49+
//[error] izumi.reflect.dottyreflection.InspectorBase is not a legal path
50+
//[error] since it has a member InternalTypeRefOrParamRef with possibly conflicting bounds Object{def underlying(ctx: Any): Nothing} <: ... <: Object{def underlying(ctx: Nothing): Matchable}
51+
f
52+
}
53+
}
54+
55+
private[reflect] inline def log(inline shift: Int, s: String): Unit = {
56+
inline if (valueOf[InspectorBase#debug]) println(" " * shift + " -> " + s)
57+
}
58+
59+
}

0 commit comments

Comments
 (0)