Skip to content

Commit a230912

Browse files
authored
Merge pull request #4102 from dotty-staging/improve-dependent-implicits
Improve implicit search involving SelectProtos over dependent methods
2 parents 4912ba5 + e6a403a commit a230912

File tree

2 files changed

+114
-1
lines changed

2 files changed

+114
-1
lines changed

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

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,30 @@ object ProtoTypes {
9797
abstract case class SelectionProto(name: Name, memberProto: Type, compat: Compatibility, privateOK: Boolean)
9898
extends CachedProxyType with ProtoType with ValueTypeOrProto {
9999

100+
/** Is the set of members of this type unknown? This is the case if:
101+
* 1. The type has Nothing or Wildcard as a prefix or underlying type
102+
* 2. The type has an uninstantiated TypeVar as a prefix or underlying type,
103+
* or as an upper bound of a prefix or underlying type.
104+
*/
105+
private def hasUnknownMembers(tp: Type)(implicit ctx: Context): Boolean = tp match {
106+
case tp: TypeVar => !tp.isInstantiated
107+
case tp: WildcardType => true
108+
case tp: TypeRef =>
109+
val sym = tp.symbol
110+
sym == defn.NothingClass ||
111+
!sym.isStatic && {
112+
hasUnknownMembers(tp.prefix) || {
113+
val bound = tp.info.hiBound
114+
bound.isProvisional && hasUnknownMembers(bound)
115+
}
116+
}
117+
case tp: TypeProxy => hasUnknownMembers(tp.superType)
118+
case _ => false
119+
}
120+
100121
override def isMatchedBy(tp1: Type)(implicit ctx: Context) = {
101-
name == nme.WILDCARD || {
122+
name == nme.WILDCARD || hasUnknownMembers(tp1) ||
123+
{
102124
val mbr = if (privateOK) tp1.member(name) else tp1.nonPrivateMember(name)
103125
def qualifies(m: SingleDenotation) =
104126
memberProto.isRef(defn.UnitClass) ||

tests/pos/typeclass-encoding.scala

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/** A possible type class encoding for
2+
3+
trait SemiGroup {
4+
def add(that: This): This
5+
}
6+
7+
trait Monoid extends SemiGroup {
8+
static def unit: This
9+
}
10+
11+
extend Int : Monoid {
12+
def add(that: Int) = this + that
13+
static def unit = 0
14+
}
15+
16+
extend String : Monoid {
17+
def add(that: Int) = this ++ that
18+
static def unit = ""
19+
}
20+
21+
def sum[T: Monoid](xs: List[T]): T =
22+
(instance[T, Monoid].unit /: xs)(_ `add` _)
23+
24+
*/
25+
object runtime {
26+
27+
trait TypeClass {
28+
type This
29+
type StaticPart[This]
30+
}
31+
32+
trait Implementation[From] {
33+
type This = From
34+
type Implemented <: TypeClass
35+
def inject(x: From): Implemented { type This = From }
36+
}
37+
38+
class CompanionOf[T] { type StaticPart[_] }
39+
40+
def instance[From, To <: TypeClass](
41+
implicit ev1: Implementation[From] { type Implemented = To },
42+
ev2: CompanionOf[To]): Implementation[From] { type Implemented = To } & ev2.StaticPart[From] =
43+
ev1.asInstanceOf // can we avoid the cast?
44+
45+
implicit def inject[From](x: From)(
46+
implicit ev1: Implementation[From]): ev1.Implemented { type This = From } =
47+
ev1.inject(x)
48+
}
49+
50+
object semiGroups {
51+
import runtime._
52+
53+
trait SemiGroup extends TypeClass {
54+
def add(that: This): This
55+
}
56+
57+
trait Monoid extends SemiGroup {
58+
type StaticPart[This] <: MonoidStatic[This]
59+
}
60+
abstract class MonoidStatic[This] { def unit: This }
61+
62+
implicit def companionOfMonoid: CompanionOf[Monoid] {
63+
type StaticPart[X] = MonoidStatic[X]
64+
} = new CompanionOf[Monoid] {
65+
type StaticPart[X] = MonoidStatic[X]
66+
}
67+
68+
implicit object extend_Int_Monoid extends MonoidStatic[Int] with Implementation[Int] {
69+
type Implemented = Monoid
70+
def unit: Int = 0
71+
def inject($this: Int) = new Monoid {
72+
type This = Int
73+
def add(that: This): This = $this + that
74+
}
75+
}
76+
77+
implicit object extend_String_Monoid extends MonoidStatic[String] with Implementation[String] {
78+
type Implemented = Monoid
79+
def unit = ""
80+
def inject($this: String): Monoid { type This = String } =
81+
new Monoid {
82+
type This = String
83+
def add(that: This): This = $this ++ that
84+
}
85+
}
86+
87+
def sum[T](xs: List[T])(implicit $ev: Implementation[T] { type Implemented = Monoid } ) = {
88+
(instance[T, Monoid].unit /: xs)((x, y) => inject(x) `add` y)
89+
(instance[T, Monoid].unit /: xs)((x, y) => x `add` y) // fails in scalac and previous dotc.
90+
}
91+
}

0 commit comments

Comments
 (0)