Skip to content

Commit 602ed35

Browse files
authored
Convert -Ycc to language import (#16240)
Two new experimental language imports: - captureChecking: replaces -Ycc - pureFunctions: Enables pure function syntax A -> B
2 parents ad4c4ac + fc5c0ab commit 602ed35

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+286
-150
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ class Compiler {
8181
new PatternMatcher) :: // Compile pattern matches
8282
List(new TestRecheck.Pre) :: // Test only: run rechecker, enabled under -Yrecheck-test
8383
List(new TestRecheck) :: // Test only: run rechecker, enabled under -Yrecheck-test
84-
List(new CheckCaptures.Pre) :: // Preparations for check captures phase, enabled under -Ycc
85-
List(new CheckCaptures) :: // Check captures, enabled under -Ycc
84+
List(new CheckCaptures.Pre) :: // Preparations for check captures phase, enabled under captureChecking
85+
List(new CheckCaptures) :: // Check captures, enabled under captureChecking
8686
List(new ElimOpaque, // Turn opaque into normal aliases
8787
new sjs.ExplicitJSClasses, // Make all JS classes explicit (Scala.js only)
8888
new ExplicitOuter, // Add accessors to outer classes from nested ones.

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,11 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
195195
case arg => arg.typeOpt.widen.isRepeatedParam
196196
}
197197

198-
/** Is tree a type tree of the form `=> T` or (under -Ycc) `{refs}-> T`? */
198+
/** Is tree a type tree of the form `=> T` or (under pureFunctions) `{refs}-> T`? */
199199
def isByNameType(tree: Tree)(using Context): Boolean =
200200
stripByNameType(tree) ne tree
201201

202-
/** Strip `=> T` to `T` and (under -Ycc) `{refs}-> T` to `T` */
202+
/** Strip `=> T` to `T` and (under pureFunctions) `{refs}-> T` to `T` */
203203
def stripByNameType(tree: Tree)(using Context): Tree = unsplice(tree) match
204204
case ByNameTypeTree(t1) => t1
205205
case untpd.CapturingTypeTree(_, parent) =>
@@ -400,18 +400,18 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped]
400400
}
401401
}
402402

403-
/** Under -Ycc: A builder and extractor for `=> T`, which is an alias for `{*}-> T`.
403+
/** Under pureFunctions: A builder and extractor for `=> T`, which is an alias for `{*}-> T`.
404404
* Only trees of the form `=> T` are matched; trees written directly as `{*}-> T`
405405
* are ignored by the extractor.
406406
*/
407407
object ImpureByNameTypeTree:
408-
408+
409409
def apply(tp: ByNameTypeTree)(using Context): untpd.CapturingTypeTree =
410410
untpd.CapturingTypeTree(
411-
Ident(nme.CAPTURE_ROOT).withSpan(tp.span.startPos) :: Nil, tp)
411+
untpd.captureRoot.withSpan(tp.span.startPos) :: Nil, tp)
412412

413413
def unapply(tp: Tree)(using Context): Option[ByNameTypeTree] = tp match
414-
case untpd.CapturingTypeTree(id @ Ident(nme.CAPTURE_ROOT) :: Nil, bntp: ByNameTypeTree)
414+
case untpd.CapturingTypeTree(id @ Select(_, nme.CAPTURE_ROOT) :: Nil, bntp: ByNameTypeTree)
415415
if id.span == bntp.span.startPos => Some(bntp)
416416
case _ => None
417417
end ImpureByNameTypeTree

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
145145
case Floating
146146
}
147147

148-
/** {x1, ..., xN} T (only relevant under -Ycc) */
148+
/** {x1, ..., xN} T (only relevant under captureChecking) */
149149
case class CapturingTypeTree(refs: List[Tree], parent: Tree)(implicit @constructorOnly src: SourceFile) extends TypTree
150150

151151
/** Short-lived usage in typer, does not need copy/transform/fold infrastructure */
@@ -217,7 +217,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
217217

218218
case class Infix()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Infix)
219219

220-
/** Used under -Ycc to mark impure function types `A => B` in `FunctionWithMods` */
220+
/** Used under pureFunctions to mark impure function types `A => B` in `FunctionWithMods` */
221221
case class Impure()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Impure)
222222
}
223223

@@ -492,6 +492,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
492492
def scalaAny(implicit src: SourceFile): Select = scalaDot(tpnme.Any)
493493
def javaDotLangDot(name: Name)(implicit src: SourceFile): Select = Select(Select(Ident(nme.java), nme.lang), name)
494494

495+
def captureRoot(using Context): Select =
496+
Select(scalaDot(nme.caps), nme.CAPTURE_ROOT)
497+
495498
def makeConstructor(tparams: List[TypeDef], vparamss: List[List[ValDef]], rhs: Tree = EmptyTree)(using Context): DefDef =
496499
DefDef(nme.CONSTRUCTOR, joinParams(tparams, vparamss), TypeTree(), rhs)
497500

compiler/src/dotty/tools/dotc/cc/CaptureOps.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Decorators.*, NameOps.*
99
import config.Printers.capt
1010
import util.Property.Key
1111
import tpd.*
12+
import config.Feature
1213

1314
private val Captures: Key[CaptureSet] = Key()
1415
private val BoxedType: Key[BoxedTypeCache] = Key()
@@ -120,11 +121,11 @@ extension (tp: Type)
120121
case _ =>
121122
tp
122123

123-
/** Under -Ycc, map regular function type to impure function type
124+
/** Under pureFunctions, map regular function type to impure function type
124125
*/
125-
def adaptFunctionTypeUnderCC(using Context): Type = tp match
126+
def adaptFunctionTypeUnderPureFuns(using Context): Type = tp match
126127
case AppliedType(fn, args)
127-
if ctx.settings.Ycc.value && defn.isFunctionClass(fn.typeSymbol) =>
128+
if Feature.pureFunsEnabled && defn.isFunctionClass(fn.typeSymbol) =>
128129
val fname = fn.typeSymbol.name
129130
defn.FunctionType(
130131
fname.functionArity,

compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Phases.*, DenotTransformers.*, SymDenotations.*
77
import Contexts.*, Names.*, Flags.*, Symbols.*, Decorators.*
88
import Types.*, StdNames.*, Denotations.*
99
import config.Printers.{capt, recheckr}
10-
import config.Config
10+
import config.{Config, Feature}
1111
import ast.{tpd, untpd, Trees}
1212
import Trees.*
1313
import typer.RefChecks.{checkAllOverrides, checkParents}
@@ -26,7 +26,7 @@ object CheckCaptures:
2626

2727
class Pre extends PreRecheck, SymTransformer:
2828

29-
override def isEnabled(using Context) = ctx.settings.Ycc.value
29+
override def isEnabled(using Context) = Feature.ccEnabled
3030

3131
/** Reset `private` flags of parameter accessors so that we can refine them
3232
* in Setup if they have non-empty capture sets. Special handling of some
@@ -133,7 +133,7 @@ class CheckCaptures extends Recheck, SymTransformer:
133133
import CheckCaptures.*
134134

135135
def phaseName: String = "cc"
136-
override def isEnabled(using Context) = ctx.settings.Ycc.value
136+
override def isEnabled(using Context) = Feature.ccEnabled
137137

138138
def newRechecker()(using Context) = CaptureChecker(ctx)
139139

@@ -148,7 +148,7 @@ class CheckCaptures extends Recheck, SymTransformer:
148148
/** Check overrides again, taking capture sets into account.
149149
* TODO: Can we avoid doing overrides checks twice?
150150
* We need to do them here since only at this phase CaptureTypes are relevant
151-
* But maybe we can then elide the check during the RefChecks phase if -Ycc is set?
151+
* But maybe we can then elide the check during the RefChecks phase under captureChecking?
152152
*/
153153
def checkOverrides = new TreeTraverser:
154154
def traverse(t: Tree)(using Context) =

compiler/src/dotty/tools/dotc/config/Config.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ object Config {
240240
*/
241241
inline val printCaptureSetsAsPrefix = true
242242

243-
/** If true, allow mappping capture set variables under -Ycc with maps that are neither
243+
/** If true, allow mappping capture set variables under captureChecking with maps that are neither
244244
* bijective nor idempotent. We currently do now know how to do this correctly in all
245245
* cases, though.
246246
*/

compiler/src/dotty/tools/dotc/config/Feature.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ object Feature:
2828
val symbolLiterals = deprecated("symbolLiterals")
2929
val fewerBraces = experimental("fewerBraces")
3030
val saferExceptions = experimental("saferExceptions")
31+
val pureFunctions = experimental("pureFunctions")
32+
val captureChecking = experimental("captureChecking")
33+
34+
val globalOnlyImports: Set[TermName] = Set(pureFunctions, captureChecking)
3135

3236
/** Is `feature` enabled by by a command-line setting? The enabling setting is
3337
*
@@ -75,6 +79,11 @@ object Feature:
7579

7680
def scala2ExperimentalMacroEnabled(using Context) = enabled(scala2macros)
7781

82+
def pureFunsEnabled(using Context) =
83+
enabled(pureFunctions) || ccEnabled
84+
85+
def ccEnabled(using Context) = enabled(captureChecking)
86+
7887
def sourceVersionSetting(using Context): SourceVersion =
7988
SourceVersion.valueOf(ctx.settings.source.value)
8089

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,8 @@ private sealed trait YSettings:
328328
val YcheckInit: Setting[Boolean] = BooleanSetting("-Ysafe-init", "Ensure safe initialization of objects")
329329
val YrequireTargetName: Setting[Boolean] = BooleanSetting("-Yrequire-targetName", "Warn if an operator is defined without a @targetName annotation")
330330
val YrecheckTest: Setting[Boolean] = BooleanSetting("-Yrecheck-test", "Run basic rechecking (internal test only)")
331-
val Ycc: Setting[Boolean] = BooleanSetting("-Ycc", "Check captured references (warning: extremely experimental and unstable)")
332-
val YccDebug: Setting[Boolean] = BooleanSetting("-Ycc-debug", "Used in conjunction with -Ycc, debug info for captured references")
333-
val YccNoAbbrev: Setting[Boolean] = BooleanSetting("-Ycc-no-abbrev", "Used in conjunction with -Ycc, suppress type abbreviations")
331+
val YccDebug: Setting[Boolean] = BooleanSetting("-Ycc-debug", "Used in conjunction with captureChecking language import, debug info for captured references")
332+
val YccNoAbbrev: Setting[Boolean] = BooleanSetting("-Ycc-no-abbrev", "Used in conjunction with captureChecking language import, suppress type abbreviations")
334333

335334
/** Area-specific debug output */
336335
val YexplainLowlevel: Setting[Boolean] = BooleanSetting("-Yexplain-lowlevel", "When explaining type errors, show types at a lower level.")

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import typer.ImportInfo.RootRef
1414
import Comments.CommentsContext
1515
import Comments.Comment
1616
import util.Spans.NoSpan
17+
import config.Feature
1718
import Symbols.requiredModuleRef
1819
import cc.{CapturingType, CaptureSet, EventuallyCapturingType}
1920

@@ -469,7 +470,6 @@ class Definitions {
469470

470471
@tu lazy val andType: TypeSymbol = enterBinaryAlias(tpnme.AND, AndType(_, _))
471472
@tu lazy val orType: TypeSymbol = enterBinaryAlias(tpnme.OR, OrType(_, _, soft = false))
472-
@tu lazy val captureRoot: TermSymbol = enterPermanentSymbol(nme.CAPTURE_ROOT, AnyType).asTerm
473473

474474
/** Method representing a throw */
475475
@tu lazy val throwMethod: TermSymbol = enterMethod(OpsPackageClass, nme.THROWkw,
@@ -963,6 +963,7 @@ class Definitions {
963963
@tu lazy val CapsModule: Symbol = requiredModule("scala.caps")
964964
@tu lazy val Caps_unsafeBox: Symbol = CapsModule.requiredMethod("unsafeBox")
965965
@tu lazy val Caps_unsafeUnbox: Symbol = CapsModule.requiredMethod("unsafeUnbox")
966+
@tu lazy val captureRoot: TermSymbol = CapsModule.requiredValue("*")
966967

967968
// Annotation base classes
968969
@tu lazy val AnnotationClass: ClassSymbol = requiredClass("scala.annotation.Annotation")
@@ -976,7 +977,6 @@ class Definitions {
976977
@tu lazy val BooleanBeanPropertyAnnot: ClassSymbol = requiredClass("scala.beans.BooleanBeanProperty")
977978
@tu lazy val BodyAnnot: ClassSymbol = requiredClass("scala.annotation.internal.Body")
978979
@tu lazy val CapabilityAnnot: ClassSymbol = requiredClass("scala.annotation.capability")
979-
@tu lazy val CaptureCheckedAnnot: ClassSymbol = requiredClass("scala.annotation.internal.CaptureChecked")
980980
@tu lazy val ChildAnnot: ClassSymbol = requiredClass("scala.annotation.internal.Child")
981981
@tu lazy val ContextResultCountAnnot: ClassSymbol = requiredClass("scala.annotation.internal.ContextResultCount")
982982
@tu lazy val ProvisionalSuperClassAnnot: ClassSymbol = requiredClass("scala.annotation.internal.ProvisionalSuperClass")
@@ -1012,6 +1012,7 @@ class Definitions {
10121012
@tu lazy val UncheckedStableAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedStable")
10131013
@tu lazy val UncheckedVarianceAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedVariance")
10141014
@tu lazy val VolatileAnnot: ClassSymbol = requiredClass("scala.volatile")
1015+
@tu lazy val WithPureFunsAnnot: ClassSymbol = requiredClass("scala.annotation.internal.WithPureFuns")
10151016
@tu lazy val FieldMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.field")
10161017
@tu lazy val GetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.getter")
10171018
@tu lazy val ParamMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.param")
@@ -1024,7 +1025,6 @@ class Definitions {
10241025
@tu lazy val RequiresCapabilityAnnot: ClassSymbol = requiredClass("scala.annotation.internal.requiresCapability")
10251026
@tu lazy val RetainsAnnot: ClassSymbol = requiredClass("scala.annotation.retains")
10261027
@tu lazy val RetainsByNameAnnot: ClassSymbol = requiredClass("scala.annotation.retainsByName")
1027-
@tu lazy val RetainsUniversalAnnot: ClassSymbol = requiredClass("scala.annotation.retainsUniversal")
10281028

10291029
@tu lazy val JavaRepeatableAnnot: ClassSymbol = requiredClass("java.lang.annotation.Repeatable")
10301030

@@ -1160,7 +1160,7 @@ class Definitions {
11601160

11611161
/** Extractor for context function types representing by-name parameters, of the form
11621162
* `() ?=> T`.
1163-
* Under -Ycc, this becomes `() ?-> T` or `{r1, ..., rN} () ?-> T`.
1163+
* Under purefunctions, this becomes `() ?-> T` or `{r1, ..., rN} () ?-> T`.
11641164
*/
11651165
object ByNameFunction:
11661166
def apply(tp: Type)(using Context): Type = tp match
@@ -1983,9 +1983,8 @@ class Definitions {
19831983
this.initCtx = ctx
19841984
if (!isInitialized) {
19851985
// force initialization of every symbol that is synthesized or hijacked by the compiler
1986-
val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses()
1987-
++ (JavaEnumClass :: (if ctx.settings.Ycc.value then captureRoot :: Nil else Nil))
1988-
1986+
val forced =
1987+
syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses() :+ JavaEnumClass
19891988
isInitialized = true
19901989
}
19911990
addSyntheticSymbolsComments

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ object Mode {
7878
/** Use Scala2 scheme for overloading and implicit resolution */
7979
val OldOverloadingResolution: Mode = newMode(15, "OldOverloadingResolution")
8080

81-
/** Treat CapturingTypes as plain AnnotatedTypes even in phase =Ycc.
81+
/** Treat CapturingTypes as plain AnnotatedTypes even in phase CheckCaptures.
8282
* Reuses the value of OldOverloadingResolution to save Mode bits.
8383
* This is OK since OldOverloadingResolution only affects implicit search, which
8484
* is done during phases Typer and Inlinig, and IgnoreCaptures only has an

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,14 +208,13 @@ object NameOps {
208208
if str == mustHave then found = true
209209
idx + str.length
210210
else idx
211-
val start = if ctx.settings.Ycc.value then skip(0, "Impure") else 0
212-
skip(skip(start, "Erased"), "Context") == suffixStart
211+
skip(skip(skip(0, "Impure"), "Erased"), "Context") == suffixStart
213212
&& found
214213
}
215214

216215
/** Same as `funArity`, except that it returns -1 if the prefix
217216
* is not one of a (possibly empty) concatenation of a subset of
218-
* "Impure" (only under -Ycc), "Erased" and "Context" (in that order).
217+
* "Impure" (only under pureFunctions), "Erased" and "Context" (in that order).
219218
*/
220219
private def checkedFunArity(suffixStart: Int)(using Context): Int =
221220
if isFunctionPrefix(suffixStart) then funArity(suffixStart) else -1

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ object StdNames {
425425
val bytes: N = "bytes"
426426
val canEqual_ : N = "canEqual"
427427
val canEqualAny : N = "canEqualAny"
428+
val caps: N = "caps"
428429
val checkInitialized: N = "checkInitialized"
429430
val classOf: N = "classOf"
430431
val classType: N = "classType"

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4238,7 +4238,7 @@ object Types {
42384238
final val Unknown: DependencyStatus = 0 // not yet computed
42394239
final val NoDeps: DependencyStatus = 1 // no dependent parameters found
42404240
final val FalseDeps: DependencyStatus = 2 // all dependent parameters are prefixes of non-depended alias types
4241-
final val CaptureDeps: DependencyStatus = 3 // dependencies in capture sets under -Ycc, otherwise only false dependencoes
4241+
final val CaptureDeps: DependencyStatus = 3 // dependencies in capture sets under captureChecking, otherwise only false dependencoes
42424242
final val TrueDeps: DependencyStatus = 4 // some truly dependent parameters exist
42434243
final val StatusMask: DependencyStatus = 7 // the bits indicating actual dependency status
42444244
final val Provisional: DependencyStatus = 8 // set if dependency status can still change due to type variable instantiations

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import ast.{Trees, tpd, untpd}
3232
import Trees._
3333
import Decorators._
3434
import transform.SymUtils._
35-
import cc.adaptFunctionTypeUnderCC
35+
import cc.adaptFunctionTypeUnderPureFuns
3636

3737
import dotty.tools.tasty.{TastyBuffer, TastyReader}
3838
import TastyBuffer._
@@ -87,8 +87,8 @@ class TreeUnpickler(reader: TastyReader,
8787
/** The root owner tree. See `OwnerTree` class definition. Set by `enterTopLevel`. */
8888
private var ownerTree: OwnerTree = _
8989

90-
/** Was unpickled class compiled with -Ycc? */
91-
private var wasCaptureChecked: Boolean = false
90+
/** Was unpickled class compiled with pureFunctions? */
91+
private var knowsPureFuns: Boolean = false
9292

9393
private def registerSym(addr: Addr, sym: Symbol) =
9494
symAtAddr(addr) = sym
@@ -489,11 +489,11 @@ class TreeUnpickler(reader: TastyReader,
489489
def readTermRef()(using Context): TermRef =
490490
readType().asInstanceOf[TermRef]
491491

492-
/** Under -Ycc, map all function types to impure function types,
493-
* unless the unpickled class was also compiled with -Ycc.
492+
/** Under pureFunctions, map all function types to impure function types,
493+
* unless the unpickled class was also compiled with pureFunctions.
494494
*/
495495
private def postProcessFunction(tp: Type)(using Context): Type =
496-
if wasCaptureChecked then tp else tp.adaptFunctionTypeUnderCC
496+
if knowsPureFuns then tp else tp.adaptFunctionTypeUnderPureFuns
497497

498498
// ------ Reading definitions -----------------------------------------------------
499499

@@ -642,8 +642,8 @@ class TreeUnpickler(reader: TastyReader,
642642
}
643643
registerSym(start, sym)
644644
if (isClass) {
645-
if sym.owner.is(Package) && annots.exists(_.hasSymbol(defn.CaptureCheckedAnnot)) then
646-
wasCaptureChecked = true
645+
if sym.owner.is(Package) && annots.exists(_.hasSymbol(defn.WithPureFunsAnnot)) then
646+
knowsPureFuns = true
647647
sym.completer.withDecls(newScope)
648648
forkAt(templateStart).indexTemplateParams()(using localContext(sym))
649649
}

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import scala.collection.mutable
3333
import scala.collection.mutable.ListBuffer
3434
import scala.annotation.switch
3535
import reporting._
36-
import cc.adaptFunctionTypeUnderCC
36+
import cc.adaptFunctionTypeUnderPureFuns
3737

3838
object Scala2Unpickler {
3939

@@ -826,7 +826,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
826826
}
827827
else if args.nonEmpty then
828828
tycon.safeAppliedTo(EtaExpandIfHK(sym.typeParams, args.map(translateTempPoly)))
829-
.adaptFunctionTypeUnderCC
829+
.adaptFunctionTypeUnderPureFuns
830830
else if (sym.typeParams.nonEmpty) tycon.EtaExpand(sym.typeParams)
831831
else tycon
832832
case TYPEBOUNDStpe =>

0 commit comments

Comments
 (0)