Skip to content

Commit d64766f

Browse files
committed
Relax method signature matching under Mode.CheckBoundsOrSelfType
1 parent 0293318 commit d64766f

File tree

5 files changed

+405
-3
lines changed

5 files changed

+405
-3
lines changed

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,8 @@ class CheckRealizable(using Context) {
131131
/** `Realizable` if `tp` has good bounds, a `HasProblem...` instance
132132
* pointing to a bad bounds member otherwise. "Has good bounds" means:
133133
*
134-
* - all type members have good bounds (except for opaque helpers)
135-
* - all refinements of the underlying type have good bounds (except for opaque companions)
134+
* - all type members have good bounds
135+
* - all refinements of the underlying type have good bounds
136136
* - all base types are class types, and if their arguments are wildcards
137137
* they have good bounds.
138138
* - base types do not appear in multiple instances with different arguments.

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

+6-1
Original file line numberDiff line numberDiff line change
@@ -2134,11 +2134,16 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
21342134
// resort to reflection to invoke the member. And Java reflection needs to know exact
21352135
// erased parameter types. See neg/i12211.scala. Other reflection algorithms could
21362136
// conceivably dispatch without knowing precise parameter signatures. One can signal
2137-
// this by inheriting from the `scala.reflect.SignatureCanBeImprecise` marker trait,
2137+
// this by inheriting from the `scala.Selectable.WithoutPreciseParameterTypes` marker trait,
21382138
// in which case the signature test is elided.
2139+
// We also relax signature checking when checking bounds,
2140+
// for instance in tests/pos/i17222.izumi.min.scala
2141+
// the `go` method info as seen from `Foo` is `>: (in: Any): Unit <: (Nothing): Unit`
2142+
// So the parameter types conform but their signatures don't match.
21392143
def sigsOK(symInfo: Type, info2: Type) =
21402144
tp2.underlyingClassRef(refinementOK = true).member(name).exists
21412145
|| tp2.derivesFrom(defn.WithoutPreciseParameterTypesClass)
2146+
|| ctx.mode.is(Mode.CheckBoundsOrSelfType)
21422147
|| symInfo.isInstanceOf[MethodType]
21432148
&& symInfo.signature.consistentParams(info2.signature)
21442149

tests/pos/i17222.izumi.min.scala

+7
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]
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)