Skip to content

Commit

Permalink
Relax method signature matching under Mode.CheckBoundsOrSelfType
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand committed Nov 18, 2024
1 parent 0293318 commit d64766f
Show file tree
Hide file tree
Showing 5 changed files with 405 additions and 3 deletions.
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ class CheckRealizable(using Context) {
/** `Realizable` if `tp` has good bounds, a `HasProblem...` instance
* pointing to a bad bounds member otherwise. "Has good bounds" means:
*
* - all type members have good bounds (except for opaque helpers)
* - all refinements of the underlying type have good bounds (except for opaque companions)
* - all type members have good bounds
* - all refinements of the underlying type have good bounds
* - all base types are class types, and if their arguments are wildcards
* they have good bounds.
* - base types do not appear in multiple instances with different arguments.
Expand Down
7 changes: 6 additions & 1 deletion compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2134,11 +2134,16 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
// resort to reflection to invoke the member. And Java reflection needs to know exact
// erased parameter types. See neg/i12211.scala. Other reflection algorithms could
// conceivably dispatch without knowing precise parameter signatures. One can signal
// this by inheriting from the `scala.reflect.SignatureCanBeImprecise` marker trait,
// this by inheriting from the `scala.Selectable.WithoutPreciseParameterTypes` marker trait,
// in which case the signature test is elided.
// We also relax signature checking when checking bounds,
// for instance in tests/pos/i17222.izumi.min.scala
// the `go` method info as seen from `Foo` is `>: (in: Any): Unit <: (Nothing): Unit`
// So the parameter types conform but their signatures don't match.
def sigsOK(symInfo: Type, info2: Type) =
tp2.underlyingClassRef(refinementOK = true).member(name).exists
|| tp2.derivesFrom(defn.WithoutPreciseParameterTypesClass)
|| ctx.mode.is(Mode.CheckBoundsOrSelfType)
|| symInfo.isInstanceOf[MethodType]
&& symInfo.signature.consistentParams(info2.signature)

Expand Down
7 changes: 7 additions & 0 deletions tests/pos/i17222.izumi.min.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Foo:
type In
type Bar = { def go(in: In): Unit }
type False = false

class Test:
def t1: Unit = valueOf[Foo#False]
59 changes: 59 additions & 0 deletions tests/pos/i17222.izumi.rep/InspectorBase.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package izumi.reflect.dottyreflection

import scala.quoted.Quotes

trait InspectorBase extends ReflectionUtil {

val qctx: Quotes
import qctx.reflect._

protected def shift: Int

// FIXME reimplement TrivialMacroLogger on Scala 3
inline def debug: debug = valueOf[debug]
final type debug = false

// println instead of report.info because report.info eats all the subsequent report.info's after first.
inline final protected def logStart(inline s: String): Unit = {
inline if (debug) println(" " * shift + currentPositionStr + s)
}

inline final protected def log(inline s: String): Unit = {
inline if (debug) println(" " * shift + currentPositionStr + " -> " + s)
}

inline final protected def logTpeAttrs[T](inline typeRepr: TypeRepr): Unit = {
inline if (debug) {
val tree = TypeTree.of(using typeRepr.asType)
val symbol = tree.symbol
System
.err.println(
currentPositionStr + ": " +
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}"
)
}
}

private def currentPositionStr: String = {
val pos = qctx.reflect.Position.ofMacroExpansion
s"${pos.sourceFile.name}:${pos.endLine}"
}

}

object InspectorBase {

private[reflect] inline def ifDebug[A](inline f: => Unit): Unit = {
inline if (valueOf[InspectorBase#debug]) {
//[error] ^^^^^^^^^^^^^
//[error] izumi.reflect.dottyreflection.InspectorBase is not a legal path
//[error] since it has a member InternalTypeRefOrParamRef with possibly conflicting bounds Object{def underlying(ctx: Any): Nothing} <: ... <: Object{def underlying(ctx: Nothing): Matchable}
f
}
}

private[reflect] inline def log(inline shift: Int, s: String): Unit = {
inline if (valueOf[InspectorBase#debug]) println(" " * shift + " -> " + s)
}

}
Loading

0 comments on commit d64766f

Please sign in to comment.