Skip to content

Commit 4f08b68

Browse files
committed
Fix #2232 - Don't check AndTypes in liftToClasses
The purpose of liftToClasses is just to aggregate two types into one. No attempt at checking well-formedness is necessary.
1 parent 7227eb5 commit 4f08b68

File tree

3 files changed

+50
-8
lines changed

3 files changed

+50
-8
lines changed

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2219,7 +2219,7 @@ object Types {
22192219

22202220
def derivedAndType(tp1: Type, tp2: Type)(implicit ctx: Context): Type =
22212221
if ((tp1 eq this.tp1) && (tp2 eq this.tp2)) this
2222-
else AndType.make(tp1, tp2)
2222+
else AndType.make(tp1, tp2, AndType.apply)
22232223

22242224
def derived_& (tp1: Type, tp2: Type)(implicit ctx: Context): Type =
22252225
if ((tp1 eq this.tp1) && (tp2 eq this.tp2)) this
@@ -2234,21 +2234,26 @@ object Types {
22342234
final class CachedAndType(tp1: Type, tp2: Type) extends AndType(tp1, tp2)
22352235

22362236
object AndType {
2237-
def apply(tp1: Type, tp2: Type)(implicit ctx: Context) = {
2237+
def apply(tp1: Type, tp2: Type)(implicit ctx: Context): AndType = {
22382238
assert(tp1.isValueType && tp2.isValueType, i"$tp1 & $tp2 / " + s"$tp1 & $tp2")
22392239
unchecked(tp1, tp2)
22402240
}
2241-
def unchecked(tp1: Type, tp2: Type)(implicit ctx: Context) = {
2241+
2242+
def unchecked(tp1: Type, tp2: Type)(implicit ctx: Context): AndType = {
22422243
assertUnerased()
22432244
unique(new CachedAndType(tp1, tp2))
22442245
}
2245-
def make(tp1: Type, tp2: Type)(implicit ctx: Context): Type =
2246+
2247+
/** Make an AndType using `op` unless clearly unnecessary (i.e. without
2248+
* going through `&`).
2249+
*/
2250+
def make(tp1: Type, tp2: Type, op: (Type, Type) => AndType)(implicit ctx: Context): Type =
22462251
if ((tp1 eq tp2) || (tp2 eq defn.AnyType))
22472252
tp1
22482253
else if (tp1 eq defn.AnyType)
22492254
tp2
22502255
else
2251-
apply(tp1, tp2)
2256+
op(tp1, tp2)
22522257
}
22532258

22542259
abstract case class OrType(tp1: Type, tp2: Type) extends CachedGroundType with AndOrType {

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,18 +374,18 @@ trait ImplicitRunInfo { self: RunInfo =>
374374
case tp: TypeRef if tp.symbol.isAbstractOrAliasType =>
375375
val pre = tp.prefix
376376
def joinClass(tp: Type, cls: ClassSymbol) =
377-
AndType.make(tp, cls.typeRef.asSeenFrom(pre, cls.owner))
377+
AndType.make(tp, cls.typeRef.asSeenFrom(pre, cls.owner), AndType.unchecked)
378378
val lead = if (tp.prefix eq NoPrefix) defn.AnyType else apply(tp.prefix)
379379
(lead /: tp.classSymbols)(joinClass)
380380
case tp: TypeVar =>
381381
apply(tp.underlying)
382382
case tp: HKApply =>
383383
def applyArg(arg: Type) = arg match {
384-
case TypeBounds(lo, hi) => AndType.make(lo, hi)
384+
case TypeBounds(lo, hi) => AndType.make(lo, hi, AndType.unchecked)
385385
case _: WildcardType => defn.AnyType
386386
case _ => arg
387387
}
388-
(apply(tp.tycon) /: tp.args)((tc, arg) => AndType.make(tc, applyArg(arg)))
388+
(apply(tp.tycon) /: tp.args)((tc, arg) => AndType.make(tc, applyArg(arg), AndType.unchecked))
389389
case tp: TypeLambda =>
390390
apply(tp.resType)
391391
case _ =>

tests/neg/i2232.scala

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
object Cats {
2+
trait Trivial[A]
3+
implicit def trivial[A]: Trivial[A] = new Trivial[A] { }
4+
5+
type Obj[C[_[_[_], _[_, _]]]] =
6+
[A] => C[({type l[c0[_], c1[_, _]] = c0[A] })#l]
7+
type Cat[C[_[_[_], _[_, _]]]] =
8+
[A, B] => C[({type l[c0[_], c1[_, _]] = c1[A, B]})#l]
9+
10+
trait Category[C[_[_[_], _[_, _]]]] {
11+
type -> = Cats.Cat[C]
12+
type Obj = Cats.Obj[C]
13+
14+
def id[A: Obj]: A -> A
15+
def andThen[A, B, C](ab: A -> B, bc: B -> C): A -> C
16+
}
17+
18+
object Category {
19+
type ByF[F[_, _]] = Category[_] { type -> = F }
20+
}
21+
22+
type Scal[f[_[_], _[_, _]]] = f[Trivial, Function1]
23+
24+
implicit val scal: Category[Scal] = new Category[Scal] {
25+
def id[A: Obj]: A -> A = a => a
26+
def andThen[A, B, C](ab: A -> B, bc: B -> C): A -> C = ab.andThen(bc)
27+
}
28+
29+
implicit class CategoryOps[F[_, _], A, B](ab: F[A, B]) {
30+
def >>>[C](bc: F[B, C])(implicit F: Category.ByF[F]): F[A, C] =
31+
F.andThen(ab, bc)
32+
}
33+
34+
val f: Int => Int = _ + 1
35+
val g: Int => String = _.toString
36+
f >>> g
37+
}

0 commit comments

Comments
 (0)