@@ -26,7 +26,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
26
26
/** Handlers to synthesize implicits for special types */
27
27
type SpecialHandler = (Type , Span ) => Context ?=> TreeWithErrors
28
28
private type SpecialHandlers = List [(ClassSymbol , SpecialHandler )]
29
-
29
+
30
30
val synthesizedClassTag : SpecialHandler = (formal, span) =>
31
31
formal.argInfos match
32
32
case arg :: Nil =>
@@ -278,28 +278,15 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
278
278
279
279
private def productMirror (mirroredType : Type , formal : Type , span : Span )(using Context ): TreeWithErrors =
280
280
281
- /** do all parts match the class symbol? */
282
- def acceptable (tp : Type , cls : Symbol ): Boolean = tp match
283
- case tp : HKTypeLambda if tp.resultType.isInstanceOf [HKTypeLambda ] => false
284
- case tp : TypeProxy => acceptable(tp.underlying, cls)
285
- case OrType (tp1, tp2) => acceptable(tp1, cls) && acceptable(tp2, cls)
286
- case _ => tp.classSymbol eq cls
287
-
288
- /** for a case class, if it will have an anonymous mirror,
289
- * check that its constructor can be accessed
290
- * from the calling scope.
291
- */
292
- def canAccessCtor (cls : Symbol ): Boolean =
293
- ! genAnonyousMirror(cls) || {
294
- def isAccessible (sym : Symbol ): Boolean = ctx.owner.isContainedIn(sym)
295
- def isSub (sym : Symbol ): Boolean = ctx.owner.ownersIterator.exists(_.derivesFrom(sym))
296
- val ctor = cls.primaryConstructor
297
- (! ctor.isOneOf(Private | Protected ) || isSub(cls)) // we cant access the ctor because we do not extend cls
298
- && (! ctor.privateWithin.exists || isAccessible(ctor.privateWithin)) // check scope is compatible
299
- }
300
-
301
- def genAnonyousMirror (cls : Symbol ): Boolean =
302
- cls.is(Scala2x ) || cls.linkedClass.is(Case )
281
+ def whyNotAcceptableType (tp : Type , cls : Symbol ): String = tp match
282
+ case tp : HKTypeLambda if tp.resultType.isInstanceOf [HKTypeLambda ] =>
283
+ i " its subpart $tp is not a supported kind (either `*` or `* -> *`) "
284
+ case tp : TypeProxy => whyNotAcceptableType(tp.underlying, cls)
285
+ case OrType (tp1, tp2) =>
286
+ Seq (tp1, tp2).map(whyNotAcceptableType(_, cls)).find(_.nonEmpty).getOrElse(" " )
287
+ case _ =>
288
+ if tp.classSymbol eq cls then " "
289
+ else i " a subpart reduces to the more precise ${tp.classSymbol}, expected $cls"
303
290
304
291
def makeProductMirror (cls : Symbol ): TreeWithErrors =
305
292
val accessors = cls.caseAccessors.filterNot(_.isAllOf(PrivateLocal ))
@@ -318,61 +305,63 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
318
305
.refinedWith(tpnme.MirroredElemTypes , TypeAlias (elemsType))
319
306
.refinedWith(tpnme.MirroredElemLabels , TypeAlias (elemsLabels))
320
307
val mirrorRef =
321
- if (genAnonyousMirror( cls)) anonymousMirror(monoType, ExtendsProductMirror , span)
322
- else companionPath(mirroredType , span)
308
+ if cls.useCompanionAsProductMirror then companionPath(mirroredType , span)
309
+ else anonymousMirror(monoType, ExtendsProductMirror , span)
323
310
withNoErrors(mirrorRef.cast(mirrorType))
324
311
end makeProductMirror
325
312
326
- def getError (cls : Symbol ): String =
327
- val reason = if ! cls.isGenericProduct then
328
- i " because ${cls.whyNotGenericProduct}"
329
- else if ! canAccessCtor(cls) then
330
- i " because the constructor of $cls is innaccessible from the calling scope. "
331
- else
332
- " "
333
- i " $cls is not a generic product $reason"
334
- end getError
313
+ /** widen TermRef to see if they are an alias to an enum singleton */
314
+ def isEnumSingletonRef (tp : Type )(using Context ): Boolean = tp match
315
+ case tp : TermRef =>
316
+ val sym = tp.termSymbol
317
+ sym.isEnumCase || (! tp.isOverloaded && isEnumSingletonRef(tp.underlying.widenExpr))
318
+ case _ => false
335
319
336
320
mirroredType match
337
321
case AndType (tp1, tp2) =>
338
322
orElse(productMirror(tp1, formal, span), productMirror(tp2, formal, span))
339
323
case _ =>
340
- if mirroredType.termSymbol.is(CaseVal ) then
341
- val module = mirroredType.termSymbol
342
- val modulePath = pathFor(mirroredType).withSpan(span)
343
- if module.info.classSymbol.is(Scala2x ) then
344
- val mirrorType = mirrorCore(defn.Mirror_SingletonProxyClass , mirroredType, mirroredType, module.name, formal)
345
- val mirrorRef = New (defn.Mirror_SingletonProxyClass .typeRef, modulePath :: Nil )
324
+ val cls = mirroredType.classSymbol
325
+ if isEnumSingletonRef(mirroredType) || cls.isAllOf(Case | Module ) then
326
+ val (singleton, singletonRef) =
327
+ if mirroredType.termSymbol.exists then (mirroredType.termSymbol, mirroredType)
328
+ else (cls.sourceModule, cls.sourceModule.reachableTermRef)
329
+ val singletonPath = pathFor(singletonRef).withSpan(span)
330
+ if singleton.info.classSymbol.is(Scala2x ) then // could be Scala 3 alias of Scala 2 case object.
331
+ val mirrorType = mirrorCore(defn.Mirror_SingletonProxyClass , mirroredType, mirroredType, singleton.name, formal)
332
+ val mirrorRef = New (defn.Mirror_SingletonProxyClass .typeRef, singletonPath :: Nil )
346
333
withNoErrors(mirrorRef.cast(mirrorType))
347
334
else
348
- val mirrorType = mirrorCore(defn.Mirror_SingletonClass , mirroredType, mirroredType, module .name, formal)
349
- withNoErrors(modulePath .cast(mirrorType))
335
+ val mirrorType = mirrorCore(defn.Mirror_SingletonClass , mirroredType, mirroredType, singleton .name, formal)
336
+ withNoErrors(singletonPath .cast(mirrorType))
350
337
else
351
- val cls = mirroredType.classSymbol
352
- if acceptable(mirroredType, cls)
353
- && cls.isGenericProduct
354
- && canAccessCtor(cls)
355
- then
356
- makeProductMirror(cls)
357
- else
358
- (EmptyTree , List (getError(cls)))
338
+ val acceptableMsg = whyNotAcceptableType(mirroredType, cls)
339
+ if acceptableMsg.isEmpty then
340
+ if cls.isGenericProduct then makeProductMirror(cls)
341
+ else withErrors(i " $cls is not a generic product because ${cls.whyNotGenericProduct}" )
342
+ else withErrors(i " type $mirroredType is not a generic product because $acceptableMsg" )
359
343
end productMirror
360
344
361
345
private def sumMirror (mirroredType : Type , formal : Type , span : Span )(using Context ): TreeWithErrors =
362
346
363
347
val cls = mirroredType.classSymbol
364
- val useCompanion = cls.useCompanionAsSumMirror
365
- val declScope = if useCompanion then cls.linkedClass else ctx.owner
366
- val clsIsGenericSum = cls.isGenericSum(declScope)
367
-
368
- def acceptable (tp : Type ): Boolean = tp match
369
- case tp : TermRef => false
370
- case tp : HKTypeLambda if tp.resultType.isInstanceOf [HKTypeLambda ] => false
371
- case tp : TypeProxy => acceptable(tp.underlying)
372
- case OrType (tp1, tp2) => acceptable(tp1) && acceptable(tp2)
373
- case _ => tp.classSymbol eq cls
374
-
375
- if acceptable(mirroredType) && clsIsGenericSum then
348
+ val clsIsGenericSum = cls.isGenericSum
349
+
350
+ def whyNotAcceptableType (tp : Type ): String = tp match
351
+ case tp : TermRef => i " its subpart $tp is a term reference "
352
+ case tp : HKTypeLambda if tp.resultType.isInstanceOf [HKTypeLambda ] =>
353
+ i " its subpart $tp is not a supported kind (either `*` or `* -> *`) "
354
+ case tp : TypeProxy => whyNotAcceptableType(tp.underlying)
355
+ case OrType (tp1, tp2) =>
356
+ Seq (tp1, tp2).map(whyNotAcceptableType).find(_.nonEmpty).getOrElse(" " )
357
+ case _ =>
358
+ if tp.classSymbol eq cls then " "
359
+ else i " a subpart reduces to the more precise ${tp.classSymbol}, expected $cls"
360
+
361
+
362
+ val acceptableMsg = whyNotAcceptableType(mirroredType)
363
+
364
+ if acceptableMsg.isEmpty && clsIsGenericSum then
376
365
val elemLabels = cls.children.map(c => ConstantType (Constant (c.name.toString)))
377
366
378
367
def solve (sym : Symbol ): Type = sym match
@@ -423,12 +412,14 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
423
412
.refinedWith(tpnme.MirroredElemTypes , TypeAlias (elemsType))
424
413
.refinedWith(tpnme.MirroredElemLabels , TypeAlias (TypeOps .nestedPairs(elemLabels)))
425
414
val mirrorRef =
426
- if useCompanion then companionPath(mirroredType, span)
415
+ if cls.useCompanionAsSumMirror then companionPath(mirroredType, span)
427
416
else anonymousMirror(monoType, ExtendsSumMirror , span)
428
417
withNoErrors(mirrorRef.cast(mirrorType))
418
+ else if acceptableMsg.nonEmpty then
419
+ withErrors(i " type $mirroredType is not a generic sum because $acceptableMsg" )
429
420
else if ! clsIsGenericSum then
430
- ( EmptyTree , List ( i " $cls is not a generic sum because ${cls.whyNotGenericSum(declScope)} " ) )
431
- else
421
+ withErrors( i " $cls is not a generic sum because ${cls.whyNotGenericSum} " )
422
+ else
432
423
EmptyTreeNoError
433
424
end sumMirror
434
425
@@ -595,7 +586,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
595
586
tp.baseType(cls)
596
587
val base = baseWithRefinements(formal)
597
588
val result =
598
- if (base <:< formal.widenExpr)
589
+ if (base <:< formal.widenExpr)
599
590
// With the subtype test we enforce that the searched type `formal` is of the right form
600
591
handler(base, span)
601
592
else EmptyTreeNoError
@@ -609,19 +600,20 @@ end Synthesizer
609
600
610
601
object Synthesizer :
611
602
612
- /** Tuple used to store the synthesis result with a list of errors. */
603
+ /** Tuple used to store the synthesis result with a list of errors. */
613
604
type TreeWithErrors = (Tree , List [String ])
614
605
private def withNoErrors (tree : Tree ): TreeWithErrors = (tree, List .empty)
606
+ private def withErrors (errors : String * ): TreeWithErrors = (EmptyTree , errors.toList)
615
607
616
608
private val EmptyTreeNoError : TreeWithErrors = withNoErrors(EmptyTree )
617
609
618
610
private def orElse (treeWithErrors1 : TreeWithErrors , treeWithErrors2 : => TreeWithErrors ): TreeWithErrors = treeWithErrors1 match
619
- case (tree, errors) if tree eq genericEmptyTree =>
611
+ case (tree, errors) if tree eq genericEmptyTree =>
620
612
val (tree2, errors2) = treeWithErrors2
621
613
(tree2, errors ::: errors2)
622
614
case _ => treeWithErrors1
623
615
624
- private def clearErrorsIfNotEmpty (treeWithErrors : TreeWithErrors ) = treeWithErrors match
616
+ private def clearErrorsIfNotEmpty (treeWithErrors : TreeWithErrors ) = treeWithErrors match
625
617
case (tree, _) if tree eq genericEmptyTree => treeWithErrors
626
618
case (tree, _) => withNoErrors(tree)
627
619
0 commit comments