Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Be still more careful when computing denotations of class parameters #16112

Merged
merged 1 commit into from
Sep 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 23 additions & 10 deletions compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,7 @@ object Denotations {
def aggregate[T](f: SingleDenotation => T, g: (T, T) => T): T = f(this)

type AsSeenFromResult = SingleDenotation

protected def computeAsSeenFrom(pre: Type)(using Context): SingleDenotation = {
val symbol = this.symbol
val owner = this match {
Expand Down Expand Up @@ -1120,19 +1121,31 @@ object Denotations {
then this
else if symbol.isAllOf(ClassTypeParam) then
val arg = symbol.typeRef.argForParam(pre, widenAbstract = true)
if arg.exists then
// take the argument bounds, but intersect with the symbols bounds if
// this forces nothing and gives a non-empty type.
val newBounds =
if symbol.isCompleted && !symbol.info.containsLazyRefs then
val combined @ TypeBounds(lo, hi) = symbol.info.bounds & arg.bounds
if lo frozen_<:< hi then combined
else arg.bounds
else arg.bounds
derivedSingleDenotation(symbol, newBounds, pre)
if arg.exists
then derivedSingleDenotation(symbol, normalizedArgBounds(arg.bounds), pre)
else derived(symbol.info)
else derived(symbol.info)
}

/** The argument bounds, possibly intersected with the parameter's info TypeBounds,
* if the latter is not F-bounded and does not refer to other type parameters
* of the same class, and the intersection is provably nonempty.
*/
private def normalizedArgBounds(argBounds: TypeBounds)(using Context): TypeBounds =
if symbol.isCompleted && !hasBoundsDependingOnParamsOf(symbol.owner) then
val combined @ TypeBounds(lo, hi) = symbol.info.bounds & argBounds
if (lo frozen_<:< hi) then combined
else argBounds
else argBounds

private def hasBoundsDependingOnParamsOf(cls: Symbol)(using Context): Boolean =
val acc = new TypeAccumulator[Boolean]:
def apply(x: Boolean, tp: Type): Boolean = tp match
case _: LazyRef => true
case tp: TypeRef
if tp.symbol.isAllOf(ClassTypeParam) && tp.symbol.owner == cls => true
case _ => foldOver(x, tp)
acc(false, symbol.info)
}

abstract class NonSymSingleDenotation(symbol: Symbol, initInfo: Type, override val prefix: Type) extends SingleDenotation(symbol, initInfo) {
Expand Down
8 changes: 0 additions & 8 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -442,14 +442,6 @@ object Types {
final def containsWildcardTypes(using Context) =
existsPart(_.isInstanceOf[WildcardType], StopAt.Static, forceLazy = false)

/** Does this type contain LazyRef types? */
final def containsLazyRefs(using Context) =
val acc = new TypeAccumulator[Boolean]:
def apply(x: Boolean, tp: Type): Boolean = tp match
case _: LazyRef => true
case _ => x || foldOver(x, tp)
acc(false, this)

// ----- Higher-order combinators -----------------------------------

/** Returns true if there is a part of this type that satisfies predicate `p`.
Expand Down
12 changes: 12 additions & 0 deletions tests/pos/i16105.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
trait SQLSyntaxSupport[A]

trait ResultNameSQLSyntaxProvider[S <: SQLSyntaxSupport[A], A]
trait QuerySQLSyntaxProvider[S <: SQLSyntaxSupport[A], A]{
def resultName: ResultNameSQLSyntaxProvider[S, A] = ???
}

def include(syntaxProviders: QuerySQLSyntaxProvider[_, _]*) = {
syntax(syntaxProviders.map(_.resultName): _*)
}

def syntax(resultNames: ResultNameSQLSyntaxProvider[_, _]*) = ???