Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d35d4dc

Browse files
authoredSep 9, 2021
Merge branch 'master' into check-ordinal-match
2 parents 760f27a + 2b74f88 commit d35d4dc

File tree

20 files changed

+525
-220
lines changed

20 files changed

+525
-220
lines changed
 

‎compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -702,13 +702,18 @@ object TypeOps:
702702
//
703703
// 1. Replace type parameters in T with tvars
704704
// 2. Replace non-class applied types with a tvar, bounded by its type constructor's underlying type
705+
// 3. Replace non-reducing MatchType with its bound
705706
//
706707
val approximateParent = new TypeMap {
707708
val boundTypeParams = util.HashMap[TypeRef, TypeVar]()
708709

709710
def apply(tp: Type): Type = tp.dealias match {
710-
case _: MatchType =>
711-
tp // break cycles
711+
case tp: MatchType =>
712+
val reduced = tp.reduced
713+
if reduced.exists then tp // break cycles
714+
else mapOver(tp.bound) // if the match type doesn't statically reduce
715+
// then to avoid it failing the <:<
716+
// we'll approximate by widening to its bounds
712717

713718
case tp: TypeRef if !tp.symbol.isClass =>
714719
def lo = LazyRef.of(apply(tp.underlying.loBound))
@@ -726,7 +731,7 @@ object TypeOps:
726731
tv
727732
end if
728733

729-
case AppliedType(tycon: TypeRef, _) if !tycon.dealias.typeSymbol.isClass =>
734+
case tp @ AppliedType(tycon: TypeRef, _) if !tycon.dealias.typeSymbol.isClass && !tp.isMatchAlias =>
730735

731736
// In tests/patmat/i3645g.scala, we need to tell whether it's possible
732737
// that K1 <: K[Foo]. If yes, we issue a warning; otherwise, no

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -427,10 +427,7 @@ object Types {
427427
def isMatch(using Context): Boolean = stripped match {
428428
case _: MatchType => true
429429
case tp: HKTypeLambda => tp.resType.isMatch
430-
case tp: AppliedType =>
431-
tp.tycon match
432-
case tycon: TypeRef => tycon.info.isInstanceOf[MatchAlias]
433-
case _ => false
430+
case tp: AppliedType => tp.isMatchAlias
434431
case _ => false
435432
}
436433

‎compiler/src/dotty/tools/dotc/typer/Inliner.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,9 @@ object Inliner {
304304
*/
305305
def inlineCallTrace(callSym: Symbol, pos: SourcePosition)(using Context): Tree = {
306306
assert(ctx.source == pos.source)
307-
if (callSym.is(Macro)) ref(callSym.topLevelClass.owner).select(callSym.topLevelClass.name).withSpan(pos.span)
308-
else Ident(callSym.topLevelClass.typeRef).withSpan(pos.span)
307+
val topLevelCls = callSym.topLevelClass
308+
if (callSym.is(Macro)) ref(topLevelCls.owner).select(topLevelCls.name)(using ctx.withOwner(topLevelCls.owner)).withSpan(pos.span)
309+
else Ident(topLevelCls.typeRef).withSpan(pos.span)
309310
}
310311

311312
object Intrinsics {

‎compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,10 +1375,12 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
13751375
def tpe: TypeBounds = self.tpe.asInstanceOf[Types.TypeBounds]
13761376
def low: TypeTree = self match
13771377
case self: tpd.TypeBoundsTree => self.lo
1378-
case self: tpd.TypeTree => tpd.TypeTree(self.tpe.asInstanceOf[Types.TypeBounds].lo).withSpan(self.span)
1378+
case self: tpd.TypeTree => makeTypeDef(self.tpe.asInstanceOf[Types.TypeBounds].lo)
13791379
def hi: TypeTree = self match
13801380
case self: tpd.TypeBoundsTree => self.hi
1381-
case self: tpd.TypeTree => tpd.TypeTree(self.tpe.asInstanceOf[Types.TypeBounds].hi).withSpan(self.span)
1381+
case self: tpd.TypeTree => makeTypeDef(self.tpe.asInstanceOf[Types.TypeBounds].hi)
1382+
private def makeTypeDef(tpe: Types.Type) =
1383+
tpd.TypeTree(tpe)(using ctx.withSource(self.source)).withSpan(self.span)
13821384
end extension
13831385
end TypeBoundsTreeMethods
13841386

‎project/Build.scala

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,21 +1326,38 @@ object Build {
13261326
Compile / resourceGenerators += Def.task {
13271327
import _root_.scala.sys.process._
13281328
import _root_.scala.concurrent._
1329+
import _root_.scala.concurrent.duration.Duration
13291330
import ExecutionContext.Implicits.global
1330-
val inkuireVersion = "1.0.0-M2"
1331+
val inkuireVersion = "1.0.0-M3"
13311332
val inkuireLink = s"https://github.com/VirtusLab/Inkuire/releases/download/$inkuireVersion/inkuire.js"
13321333
val inkuireDestinationFile = (Compile / resourceManaged).value / "dotty_res" / "scripts" / "inkuire.js"
13331334
sbt.IO.touch(inkuireDestinationFile)
1334-
val downloadProcess = (new java.net.URL(inkuireLink) #> inkuireDestinationFile).run()
1335-
val result: Future[Int] = Future(blocking(downloadProcess.exitValue()))
1336-
val res = try {
1337-
Await.result(result, duration.Duration(20, "sec"))
1338-
} catch {
1339-
case _: TimeoutException =>
1340-
downloadProcess.destroy()
1341-
throw new MessageOnlyException(s"Failed to fetch inkuire.js from $inkuireLink: Download timeout")
1335+
1336+
def tryFetch(retries: Int, timeout: Duration): Unit = {
1337+
val downloadProcess = (new java.net.URL(inkuireLink) #> inkuireDestinationFile).run()
1338+
val result: Future[Int] = Future(blocking(downloadProcess.exitValue()))
1339+
try {
1340+
Await.result(result, timeout) match {
1341+
case 0 =>
1342+
case res if retries > 0 =>
1343+
println(s"Failed to fetch inkuire.js from $inkuireLink: Error code $res. $retries retries left")
1344+
tryFetch(retries - 1, timeout)
1345+
case res => throw new MessageOnlyException(s"Failed to fetch inkuire.js from $inkuireLink: Error code $res")
1346+
}
1347+
} catch {
1348+
case e: TimeoutException =>
1349+
downloadProcess.destroy()
1350+
if (retries > 0) {
1351+
println(s"Failed to fetch inkuire.js from $inkuireLink: Download timeout. $retries retries left")
1352+
tryFetch(retries - 1, timeout)
1353+
}
1354+
else {
1355+
throw new MessageOnlyException(s"Failed to fetch inkuire.js from $inkuireLink: Download timeout")
1356+
}
1357+
}
13421358
}
1343-
if(res != 0) throw new MessageOnlyException(s"Failed to fetch inkuire.js from $inkuireLink: Error code $res")
1359+
1360+
tryFetch(5, Duration(60, "s"))
13441361
Seq(inkuireDestinationFile)
13451362
}.taskValue,
13461363
libraryDependencies ++= Dependencies.flexmarkDeps ++ Seq(

‎scaladoc-js/src/searchbar/PageEntry.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ case class InkuireMatch(
2525
functionName: String,
2626
packageLocation: String,
2727
pageLocation: String,
28-
entryType: String
28+
entryType: String,
29+
mq: Int
2930
)
3031

3132
object PageEntry {

‎scaladoc-js/src/searchbar/SearchbarComponent.scala

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dotty.tools.scaladoc
22

33
import org.scalajs.dom._
4+
import org.scalajs.dom.ext._
45
import org.scalajs.dom.html.Input
56
import scala.scalajs.js.timers._
67
import scala.concurrent.duration._
@@ -40,6 +41,7 @@ class SearchbarComponent(engine: SearchbarEngine, inkuireEngine: InkuireJSSearch
4041
val wrapper = document.createElement("div").asInstanceOf[html.Div]
4142
wrapper.classList.add("scaladoc-searchbar-result")
4243
wrapper.classList.add("monospace")
44+
wrapper.setAttribute("mq", m.mq.toString)
4345

4446
val resultDiv = document.createElement("div").asInstanceOf[html.Div]
4547
resultDiv.classList.add("scaladoc-searchbar-result-row")
@@ -132,7 +134,16 @@ class SearchbarComponent(engine: SearchbarEngine, inkuireEngine: InkuireJSSearch
132134
loading.appendChild(animation)
133135
properResultsDiv.appendChild(loading)
134136
inkuireEngine.query(query) { (m: InkuireMatch) =>
135-
properResultsDiv.appendChild(m.toHTML)
137+
val next = properResultsDiv.children.foldLeft[Option[Element]](None) {
138+
case (acc, child) if !acc.isEmpty => acc
139+
case (_, child) =>
140+
Option.when(child.hasAttribute("mq") && Integer.parseInt(child.getAttribute("mq")) > m.mq)(child)
141+
}
142+
next.fold {
143+
properResultsDiv.appendChild(m.toHTML)
144+
} { next =>
145+
properResultsDiv.insertBefore(m.toHTML, next)
146+
}
136147
} { (s: String) =>
137148
animation.classList.remove("loading")
138149
properResultsDiv.appendChild(s.toHTMLError)

‎scaladoc-js/src/searchbar/engine/InkuireJSSearchEngine.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ class InkuireJSSearchEngine {
2222
d.functionName.asInstanceOf[String],
2323
d.packageLocation.asInstanceOf[String],
2424
d.pageLocation.asInstanceOf[String],
25-
d.entryType.asInstanceOf[String]
25+
d.entryType.asInstanceOf[String],
26+
d.mq.asInstanceOf[Int]
2627
)
2728
}
2829

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package tests.anImplicitClass
2+
3+
implicit class AddingOps(n: Int):
4+
def inc: Int = n + 1
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package tests.caseClassesWithVars
2+
3+
case class Sheep(var numberOfLegs: Int):
4+
var name: String = "Lawrence"
5+
6+
class Goat(var numberOfLegs: Int)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package tests.justmethods
2+
3+
trait Animal
4+
5+
def whatSoundDoIMake(animal: Animal): String = "IoIo"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package test.syntaxes
2+
3+
class DoingStuffOps[A](a: A):
4+
def doStuff: Unit = ()
5+
6+
trait DoingStuffSyntax:
7+
implicit def toDoingStuffOps[A](a: A): DoingStuffOps[A] = DoingStuffOps(a)
8+
9+
trait AllSyntaxes extends DoingStuffSyntax
10+
11+
object doingstuff extends AllSyntaxes

‎scaladoc/src/dotty/tools/scaladoc/Inkuire.scala

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ import dotty.tools.scaladoc.util._
55
object Inkuire {
66

77
var db = InkuireDb(Seq.empty, Map.empty, Seq.empty, Map.empty)
8+
var implicitConversions: Seq[(Option[TypeLike], Type)] = Seq.empty
89

910
def beforeSave(): Unit = {
1011
db = db.copy(
11-
functions = db.functions.sortBy(_.hashCode),
12+
functions = functions.sortBy(_.hashCode),
1213
types = db.types.toSeq.sortBy(_._1.uuid).toMap,
13-
implicitConversions = db.implicitConversions.sortBy(_._1.uuid)
14+
implicitConversions = implicitConversions.collect {
15+
case (Some(from), to) => from -> to
16+
}.sortBy(_._1.hashCode)
1417
)
1518
}
1619

@@ -34,10 +37,59 @@ object Inkuire {
3437
case _ => e
3538
}
3639

40+
def functions: Seq[ExternalSignature] = Inkuire.db.functions.flatMap { func =>
41+
val fromConversions = Inkuire.implicitConversions.filter { ic =>
42+
func.signature.receiver.nonEmpty && matchingICTypes(ic._2, func.signature.receiver.get.typ)
43+
}.map {
44+
case (Some(from), to) =>
45+
func.copy(
46+
signature = func.signature.copy(
47+
receiver = func.signature.receiver.map { rcvr =>
48+
Contravariance(
49+
newReceiver(rcvr.typ, to, from)
50+
)
51+
}
52+
)
53+
)
54+
case (None, to) =>
55+
func.copy(
56+
signature = func.signature.copy(
57+
receiver = None
58+
)
59+
)
60+
}
61+
Seq(func) ++ fromConversions
62+
}
63+
.distinct
64+
65+
def matchingICTypes(a: TypeLike, b: TypeLike): Boolean = (a, b) match {
66+
case (a: Type, b: Type) if a.params.size == 0 && b.params.size == 0 && a.itid == b.itid => true
67+
case (a: Type, b: Type) if a.params.size == 1 && b.params.size == 1 && a.itid == b.itid =>
68+
a.params.head.typ.isInstanceOf[Type] && a.params.head.typ.asInstanceOf[Type].isVariable &&
69+
b.params.head.typ.isInstanceOf[Type] && b.params.head.typ.asInstanceOf[Type].isVariable
70+
case _ => false
71+
}
72+
73+
def newReceiver(old: TypeLike, to: TypeLike, from: TypeLike): TypeLike = (old, to) match {
74+
case (a: Type, b: Type) if a.params.size == 0 && b.params.size == 0 && a.itid == b.itid => from
75+
case (a: Type, b: Type) if a.params.size == 1 && b.params.size == 1 && a.itid == b.itid
76+
&& a.params.head.typ.isInstanceOf[Type] && a.params.head.typ.asInstanceOf[Type].isVariable &&
77+
b.params.head.typ.isInstanceOf[Type] && b.params.head.typ.asInstanceOf[Type].isVariable =>
78+
if from.isInstanceOf[Type] && from.asInstanceOf[Type].params.size == 1 && from.asInstanceOf[Type].params.head.typ.isInstanceOf[Type] && from.asInstanceOf[Type].params.head.typ.asInstanceOf[Type].isVariable then
79+
from.asInstanceOf[Type].copy(
80+
params = Seq(Contravariance(a.params.head.typ.asInstanceOf[Type]))
81+
)
82+
else if from.isInstanceOf[Type] && from.asInstanceOf[Type].isVariable then
83+
a.params.head.typ.asInstanceOf[Type]
84+
else
85+
from
86+
case _ => old
87+
}
88+
3789
case class InkuireDb(
3890
functions: Seq[ExternalSignature],
3991
types: Map[ITID, (Type, Seq[Type])],
40-
implicitConversions: Seq[(ITID, Type)],
92+
implicitConversions: Seq[(TypeLike, Type)],
4193
typeAliases: Map[ITID, TypeLike]
4294
)
4395

@@ -164,7 +216,7 @@ object Inkuire {
164216
)
165217
}
166218

167-
private def serializeConversion(conversion: (ITID, Type)): JSON = {
219+
private def serializeConversion(conversion: (TypeLike, Type)): JSON = {
168220
jsonList(
169221
Seq(
170222
serialize(conversion._1),

‎scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala

Lines changed: 1 addition & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -100,133 +100,7 @@ trait ClassLikeSupport:
100100
deprecated = classDef.symbol.isDeprecated()
101101
)
102102

103-
if summon[DocContext].args.generateInkuire then {
104-
105-
val classType: Inkuire.Type = classDef.asInkuire(Set.empty).asInstanceOf[Inkuire.Type]
106-
107-
def varName(t: Inkuire.TypeLike): Option[String] = t match {
108-
case tpe: Inkuire.Type => Some(tpe.name.name)
109-
case tl: Inkuire.TypeLambda => varName(tl.result)
110-
case _ => None
111-
}
112-
113-
val variableNames: Set[String] = classType.params.map(_.typ)
114-
.flatMap(varName(_).toList).toSet
115-
116-
val parents: Seq[Inkuire.Type] = classDef.parents.map(_.asInkuire(variableNames).asInstanceOf[Inkuire.Type])
117-
118-
val isModule = classDef.symbol.flags.is(Flags.Module)
119-
120-
if !isModule then Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(classType.itid.get, (classType, parents)))
121-
122-
classDef.symbol.declaredTypes
123-
.filter(viableSymbol)
124-
.foreach {
125-
case typeSymbol: Symbol if typeSymbol.flags.is(Flags.Opaque) =>
126-
val typ = typeSymbol.tree.asInkuire(variableNames)
127-
if typ.isInstanceOf[Inkuire.Type] then {
128-
val t = typ.asInstanceOf[Inkuire.Type]
129-
Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty)))
130-
}
131-
case typeSymbol: Symbol if !typeSymbol.isClassDef =>
132-
val typeDef = typeSymbol.tree.asInstanceOf[TypeDef]
133-
val typ = typeSymbol.tree.asInkuire(variableNames)
134-
if typ.isInstanceOf[Inkuire.Type] then {
135-
val t = typ.asInstanceOf[Inkuire.Type]
136-
val rhsTypeLike = typeDef.rhs.asInkuire(variableNames)
137-
Inkuire.db = Inkuire.db.copy(
138-
typeAliases = Inkuire.db.typeAliases.updated(t.itid.get, rhsTypeLike),
139-
types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))
140-
)
141-
}
142-
if typeDef.rhs.symbol.flags.is(Flags.JavaDefined) then
143-
val typJava = typeDef.rhs.asInkuire(variableNames)
144-
if typJava.isInstanceOf[Inkuire.Type] then {
145-
val tJava = typJava.asInstanceOf[Inkuire.Type]
146-
Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(tJava.itid.get, (tJava, Seq.empty)))
147-
}
148-
case _ =>
149-
}
150-
151-
def viableSymbol(s: Symbol): Boolean =
152-
!s.flags.is(Flags.Private) &&
153-
!s.flags.is(Flags.Protected) &&
154-
!s.flags.is(Flags.Override) &&
155-
!s.flags.is(Flags.Synthetic)
156-
157-
classDef.symbol.declaredMethods
158-
.filter(viableSymbol)
159-
.foreach {
160-
case implicitConversion: Symbol if implicitConversion.flags.is(Flags.Implicit)
161-
&& classDef.symbol.flags.is(Flags.Module)
162-
&& implicitConversion.owner.fullName == ("scala.Predef$") =>
163-
val defdef = implicitConversion.tree.asInstanceOf[DefDef]
164-
val to = defdef.returnTpt.asInkuire(variableNames)
165-
val from = defdef.paramss.flatMap(_.params).collectFirst {
166-
case v: ValDef => v.tpt.asInkuire(variableNames)
167-
}
168-
(from, to) match
169-
case (Some(from: Inkuire.Type), to: Inkuire.Type) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from.itid.get -> to))
170-
case _ =>
171-
172-
case methodSymbol: Symbol =>
173-
val defdef = methodSymbol.tree.asInstanceOf[DefDef]
174-
val methodVars = defdef.paramss.flatMap(_.params).collect {
175-
case TypeDef(name, _) => name
176-
}
177-
val vars = variableNames ++ methodVars
178-
val receiver: Option[Inkuire.TypeLike] =
179-
Some(classType)
180-
.filter(_ => !isModule)
181-
.orElse(methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt)))
182-
val sgn = Inkuire.ExternalSignature(
183-
signature = Inkuire.Signature(
184-
receiver = receiver,
185-
arguments = methodSymbol.nonExtensionTermParamLists.collect {
186-
case tpc@TermParamClause(params) if !tpc.isImplicit && !tpc.isGiven => params //TODO [Inkuire] Implicit parameters
187-
}.flatten.map(_.tpt.asInkuire(vars)),
188-
result = defdef.returnTpt.asInkuire(vars),
189-
context = Inkuire.SignatureContext(
190-
vars = vars.toSet,
191-
constraints = Map.empty //TODO [Inkuire] Type bounds
192-
)
193-
),
194-
name = methodSymbol.name,
195-
packageName = methodSymbol.dri.location,
196-
uri = methodSymbol.dri.externalLink.getOrElse(""),
197-
entryType = "def"
198-
)
199-
val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature))
200-
Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn)
201-
}
202-
203-
classDef.symbol.declaredFields
204-
.filter(viableSymbol)
205-
.foreach {
206-
case valSymbol: Symbol =>
207-
val valdef = valSymbol.tree.asInstanceOf[ValDef]
208-
val receiver: Option[Inkuire.TypeLike] =
209-
Some(classType)
210-
.filter(_ => !isModule)
211-
val sgn = Inkuire.ExternalSignature(
212-
signature = Inkuire.Signature(
213-
receiver = receiver,
214-
arguments = Seq.empty,
215-
result = valdef.tpt.asInkuire(variableNames),
216-
context = Inkuire.SignatureContext(
217-
vars = variableNames.toSet,
218-
constraints = Map.empty //TODO [Inkuire] Type bounds
219-
)
220-
),
221-
name = valSymbol.name,
222-
packageName = valSymbol.dri.location,
223-
uri = valSymbol.dri.externalLink.getOrElse(""),
224-
entryType = "val"
225-
)
226-
val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature))
227-
Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn)
228-
}
229-
}
103+
if summon[DocContext].args.generateInkuire then doInkuireStuff(classDef)
230104

231105
if signatureOnly then baseMember else baseMember.copy(
232106
members = classDef.extractPatchedMembers.sortBy(m => (m.name, m.kind.name)),

‎scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala

Lines changed: 244 additions & 64 deletions
Large diffs are not rendered by default.

‎scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ object SymOps:
1212

1313
extension (using Quotes)(sym: reflect.Symbol)
1414

15+
def isImplicitClass: Boolean =
16+
import reflect._
17+
sym.isClassDef && sym.maybeOwner != Symbol.noSymbol
18+
&& sym.maybeOwner.declaredMethods.exists { methodSymbol =>
19+
methodSymbol.name == sym.name && methodSymbol.flags.is(Flags.Implicit) && methodSymbol.flags.is(Flags.Method)
20+
}
21+
1522
def packageName: String =
1623
if (sym.isPackageDef) sym.fullName
1724
else sym.maybeOwner.packageName
@@ -91,7 +98,9 @@ object SymOps:
9198
Flags.Open -> Modifier.Open,
9299
Flags.Override -> Modifier.Override,
93100
Flags.Case -> Modifier.Case,
94-
).collect { case (flag, mod) if sym.flags.is(flag) => mod }
101+
).collect {
102+
case (flag, mod) if sym.flags.is(flag) => mod
103+
} ++ Seq(Modifier.Implicit).filter(_ => sym.isImplicitClass)
95104

96105
def isHiddenByVisibility(using dctx: DocContext): Boolean =
97106
import VisibilityScope._

‎tests/patmat/i13189.scala

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// original report
2+
def foo(opt: Option[Tuple.Tail[NonEmptyTuple]]): Unit =
3+
opt match
4+
case None => ???
5+
case Some(a) => ???
6+
7+
8+
// again with a mini-Tuple with the extra NonEmptyTupExtra parent, to test transitivity
9+
object WithExtraParent:
10+
sealed trait Tup
11+
12+
object Tup {
13+
type Tail[X <: NonEmptyTup] <: Tup = X match {
14+
case _ **: xs => xs
15+
}
16+
}
17+
18+
object EmptyTup extends Tup
19+
20+
sealed trait NonEmptyTup extends Tup
21+
sealed trait NonEmptyTupExtra extends NonEmptyTup
22+
sealed abstract class **:[+H, +T <: Tup] extends NonEmptyTupExtra
23+
24+
object **: {
25+
def unapply[H, T <: Tup](x: H **: T): (H, T) = null
26+
}
27+
28+
def foo(opt: Option[Tup.Tail[NonEmptyTup]]): Unit =
29+
opt match
30+
case None => ???
31+
case Some(a) => ???
32+
end WithExtraParent
33+
34+
35+
// again with a non-abstract parent
36+
object WithNonAbstractParent:
37+
sealed trait Tup
38+
39+
object Tup {
40+
type Tail[X <: NonEmptyTup] <: Tup = X match {
41+
case _ **: xs => xs
42+
}
43+
}
44+
45+
object EmptyTup extends Tup
46+
47+
sealed class NonEmptyTup extends Tup
48+
sealed class **:[+H, +T <: Tup] extends NonEmptyTup
49+
50+
object **: {
51+
def unapply[H, T <: Tup](x: H **: T): (H, T) = null
52+
}
53+
54+
def foo(opt: Option[Tup.Tail[NonEmptyTup]]): Unit =
55+
opt match
56+
case None => ???
57+
case Some(a) => ???
58+
end WithNonAbstractParent
59+
60+
61+
// again with multiple children, but an exhaustive match
62+
object WithExhaustiveMatch:
63+
sealed trait Tup
64+
65+
object Tup {
66+
type Tail[X <: NonEmptyTup] <: Tup = X match {
67+
case _ **: xs => xs
68+
case _ *+: xs => xs
69+
}
70+
}
71+
72+
object EmptyTup extends Tup
73+
74+
sealed trait NonEmptyTup extends Tup
75+
sealed abstract class **:[+H, +T <: Tup] extends NonEmptyTup
76+
sealed abstract class *+:[+H, +T <: Tup] extends NonEmptyTup
77+
78+
object **: {
79+
def unapply[H, T <: Tup](x: H **: T): (H, T) = null
80+
}
81+
object *+: {
82+
def unapply[H, T <: Tup](x: H *+: T): (H, T) = null
83+
}
84+
85+
def foo(opt: Option[Tup.Tail[NonEmptyTup]]): Unit =
86+
opt match
87+
case None => ???
88+
case Some(a) => ???
89+
end WithExhaustiveMatch

‎tests/pos-macros/i13477/Macro.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package mylib
2+
import scala.quoted.*
3+
4+
private[mylib] object Main:
5+
transparent inline def d(): Unit = ${interpMacro}
6+
def interpMacro(using Quotes) : Expr[Unit] = '{}
7+
8+
transparent inline def f(): Unit = Main.d()

‎tests/pos-macros/i13477/Test.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import mylib.*
2+
val x = f()
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import scala.quoted.*
2+
import scala.tasty.inspector.*
3+
4+
@main def Test = {
5+
// Artefact of the current test infrastructure
6+
// TODO improve infrastructure to avoid needing this code on each test
7+
val classpath = dotty.tools.dotc.util.ClasspathFromClassloader(this.getClass.getClassLoader).split(java.io.File.pathSeparator).find(_.contains("runWithCompiler")).get
8+
val allTastyFiles = dotty.tools.io.Path(classpath).walkFilter(_.extension == "tasty").map(_.toString).toList
9+
val tastyFiles = allTastyFiles.filter(_.contains("CanEqual2"))
10+
11+
TastyInspector.inspectTastyFiles(tastyFiles)(new MyInspector)
12+
}
13+
14+
class MyInspector extends Inspector:
15+
16+
override def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit =
17+
import quotes.reflect.*
18+
class Traverser extends TreeTraverser:
19+
override def traverseTree(tree: Tree)(owner: Symbol) =
20+
if tree.pos.startLine < 100 then
21+
super.traverseTree(tree)(owner)
22+
end Traverser
23+
24+
val traverser = new Traverser
25+
tastys.foreach { tasty =>
26+
traverser.traverseTree(tasty.ast)(tasty.ast.symbol)
27+
}
28+
29+
30+
class CanEqual2[T]

0 commit comments

Comments
 (0)
Please sign in to comment.