Skip to content

Commit fcd6314

Browse files
committed
Don't treat opaque aliases structurally
1 parent df154be commit fcd6314

File tree

2 files changed

+36
-21
lines changed

2 files changed

+36
-21
lines changed

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

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3564,39 +3564,55 @@ object Types {
35643564
pt => List.fill(n)(TypeBounds.empty), pt => defn.AnyType)
35653565

35663566
override def fromParams[PI <: ParamInfo.Of[TypeName]](params: List[PI], resultType: Type)(implicit ctx: Context): Type =
3567-
fromParams(params, resultType, useVariances = resultType.isInstanceOf[TypeBounds])
3567+
resultType match
3568+
case bounds: TypeBounds => boundsFromParams(params, bounds)
3569+
case _ => super.fromParams(params, resultType)
35683570

35693571
/** Distributes Lambda inside type bounds. Examples:
35703572
*
35713573
* type T[X] = U becomes type T = [X] -> U
35723574
* type T[X] <: U becomes type T >: Nothing <: ([X] -> U)
35733575
* type T[X] >: L <: U becomes type T >: ([X] -> L) <: ([X] -> U)
35743576
*
3575-
* @param useVariances If true, set parameter variances of the type lambda to be as in `params`,
3576-
* If false, TypeBounds types and match aliases aways get their variances set
3577-
* and type aliases get variances set if some parameter is not invariant,
3578-
* but variances of parameters of other types are determined structurally,
3579-
* by looking how the parameter is used in the result type.
3577+
* The variances of regular TypeBounds types, as well as of match aliases
3578+
* and of opaque aliases are always determined from the given parameters
3579+
* `params`. The variances of other type aliases are determined from
3580+
* the given parameters only if one of these parameters carries a `+`
3581+
* or `-` variance annotation. Type aliases without variance annotation
3582+
* are treated structurally. That is, their parameter variances are
3583+
* determined by how the parameter(s) appear in the result type.
3584+
*
3585+
* Examples:
3586+
*
3587+
* type T[X] >: A // X is invariant
3588+
* type T[X] <: List[X] // X is invariant
3589+
* type T[X] = List[X] // X is covariant (determined structurally)
3590+
* opaque type T[X] = List[X] // X is invariant
3591+
* opaque type T[+X] = List[X] // X is covariant
3592+
* type T[A, B] = A => B // A is contravariant, B is covariant (determined structurally)
3593+
* type T[A, +B] = A => B // A is invariant, B is covariant
35803594
*/
3581-
def fromParams[PI <: ParamInfo.Of[TypeName]](params: List[PI], resultType: Type, useVariances: Boolean)(implicit ctx: Context): Type = {
3595+
def boundsFromParams[PI <: ParamInfo.Of[TypeName]](params: List[PI], bounds: TypeBounds)(implicit ctx: Context): TypeBounds = {
35823596
def expand(tp: Type, useVariances: Boolean) =
35833597
if params.nonEmpty && useVariances then
35843598
apply(params.map(_.paramName), params.map(_.paramVariance))(
35853599
tl => params.map(param => toPInfo(tl.integrate(params, param.paramInfo))),
35863600
tl => tl.integrate(params, tp))
35873601
else
35883602
super.fromParams(params, tp)
3589-
resultType match {
3590-
case rt: MatchAlias =>
3591-
rt.derivedAlias(expand(rt.alias, true))
3592-
case rt: TypeAlias =>
3593-
rt.derivedAlias(expand(rt.alias, params.exists(!_.paramVariance.isEmpty)))
3594-
case rt @ TypeBounds(lo, hi) =>
3595-
rt.derivedTypeBounds(
3596-
if (lo.isRef(defn.NothingClass)) lo else expand(lo, true),
3603+
def isOpaqueAlias = params match
3604+
case (param: Symbol) :: _ => param.owner.is(Opaque)
3605+
case _ => false
3606+
bounds match {
3607+
case bounds: MatchAlias =>
3608+
bounds.derivedAlias(expand(bounds.alias, true))
3609+
case bounds: TypeAlias =>
3610+
bounds.derivedAlias(expand(bounds.alias,
3611+
isOpaqueAlias | params.exists(!_.paramVariance.isEmpty)))
3612+
case TypeBounds(lo, hi) =>
3613+
bounds.derivedTypeBounds(
3614+
if lo.isRef(defn.NothingClass) then lo else expand(lo, true),
35973615
expand(hi, true))
3598-
case rt =>
3599-
expand(rt, useVariances)
36003616
}
36013617
}
36023618
}

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,7 +1505,7 @@ class Namer { typer: Typer =>
15051505
}
15061506

15071507
def typeDefSig(tdef: TypeDef, sym: Symbol, tparamSyms: List[TypeSymbol])(implicit ctx: Context): Type = {
1508-
def abstracted(tp: Type): Type = HKTypeLambda.fromParams(tparamSyms, tp, useVariances = true)
1508+
def abstracted(tp: TypeBounds): TypeBounds = HKTypeLambda.boundsFromParams(tparamSyms, tp)
15091509
val dummyInfo1 = abstracted(TypeBounds.empty)
15101510
sym.info = dummyInfo1
15111511
sym.setFlag(Provisional)
@@ -1535,9 +1535,8 @@ class Namer { typer: Typer =>
15351535
}
15361536
sym.info = dummyInfo2
15371537

1538-
val rhsBodyType = typedAheadType(rhs).tpe
1539-
val rhsType = if (isDerived) rhsBodyType else abstracted(rhsBodyType)
1540-
val unsafeInfo = rhsType.toBounds
1538+
val rhsBodyType: TypeBounds = typedAheadType(rhs).tpe.toBounds
1539+
val unsafeInfo = if (isDerived) rhsBodyType else abstracted(rhsBodyType)
15411540
if (isDerived) sym.info = unsafeInfo
15421541
else {
15431542
sym.info = NoCompleter

0 commit comments

Comments
 (0)