Skip to content

Commit 1c4e9c2

Browse files
committed
Merge pull request #137 from dotty-staging/change/higher-kinded
Change/higher kinded
2 parents 38b00c5 + e710af6 commit 1c4e9c2

39 files changed

+888
-678
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ object Config {
2727
/** Show subtype traces for all deep subtype recursions */
2828
final val traceDeepSubTypeRecursions = false
2929

30-
final val verboseExplainSubtype = true
30+
final val verboseExplainSubtype = false
3131

3232
/** When set, use new signature-based matching.
3333
* Advantantage of doing so: It's supposed to be faster
@@ -43,4 +43,9 @@ object Config {
4343
* for large constraints.
4444
*/
4545
final val trackConstrDeps = true
46+
47+
/** Check that variances of lambda arguments match the
48+
* variance of the underlying lambda class.
49+
*/
50+
final val checkLambdaVariance = false
4651
}

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

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@ class Definitions {
3333
private def newTopClassSymbol(name: TypeName, flags: FlagSet, parents: List[TypeRef]) =
3434
completeClass(newCompleteClassSymbol(ScalaPackageClass, name, flags, parents))
3535

36+
private def newTypeField(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) =
37+
scope.enter(newSymbol(cls, name, flags, TypeBounds.empty))
38+
3639
private def newTypeParam(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) =
37-
scope.enter(newSymbol(cls, name, flags | TypeParamCreationFlags, TypeBounds.empty))
40+
newTypeField(cls, name, flags | TypeParamCreationFlags, scope)
3841

3942
private def newSyntheticTypeParam(cls: ClassSymbol, scope: MutableScope, paramFlags: FlagSet, suffix: String = "T0") =
4043
newTypeParam(cls, suffix.toTypeName.expandedName(cls), ExpandedName | paramFlags, scope)
@@ -421,59 +424,69 @@ class Definitions {
421424

422425
def functionArity(tp: Type) = tp.dealias.argInfos.length - 1
423426

424-
// ----- Higher kinds machinery ------------------------------------------
427+
// ----- LambdaXYZ traits ------------------------------------------
425428

426-
private var _hkTraits: Set[Symbol] = Set()
429+
private var myLambdaTraits: Set[Symbol] = Set()
427430

428431
/** The set of HigherKindedXYZ traits encountered so far */
429-
def hkTraits: Set[Symbol] = _hkTraits
432+
def lambdaTraits: Set[Symbol] = myLambdaTraits
430433

431-
private var hkTraitOfArity = mutable.Map[List[Int], ClassSymbol]()
434+
private var lambdaTraitForVariances = mutable.Map[List[Int], ClassSymbol]()
432435

433436
/** The HigherKinded trait corresponding to symbols `boundSyms` (which are assumed
434437
* to be the type parameters of a higher-kided type). This is a class symbol that
435438
* would be generated by the following schema.
436439
*
437-
* class HigherKindedXYZ { type v_n _$hk$0; ...; type v_n _$Hk$n }
440+
* class LambdaXYZ extends Object with P1 with ... with Pn {
441+
* type v_1 $hk$Arg0; ...; type v_N $hk$ArgN;
442+
* type Apply
443+
* }
438444
*
439445
* Here:
440446
*
441-
* - XYZ is a string with one letter for each variant of a bound symbols,
442-
* using `P` (positive variance), `N` (negative variance), `I` (invariant).
443447
* - v_i are the variances of the bound symbols (i.e. +, -, or empty).
444-
* - _$hk$i are higher-kinded parameter names, which are specially treated in type application.
448+
* - XYZ is a string of length N with one letter for each variant of a bound symbol,
449+
* using `P` (positive variance), `N` (negative variance), `I` (invariant).
450+
* - for each positive or negative variance v_i there is a parent trait Pj which
451+
* is the same as LambdaXYZ except that it has `I` in i-th position.
445452
*/
446-
def hkTrait(vcs: List[Int]) = {
453+
def lambdaTrait(vcs: List[Int]): ClassSymbol = {
454+
assert(vcs.nonEmpty)
447455

448456
def varianceFlags(v: Int) = v match {
449457
case -1 => Contravariant
450-
case 0 => Covariant
451-
case 1 => EmptyFlags
458+
case 0 => EmptyFlags
459+
case 1 => Covariant
452460
}
453461

454462
val completer = new LazyType {
455463
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
456464
val cls = denot.asClass.classSymbol
457465
val paramDecls = newScope
458466
for (i <- 0 until vcs.length)
459-
newTypeParam(cls, tpnme.higherKindedParamName(i), EmptyFlags, paramDecls)
460-
denot.info = ClassInfo(ScalaPackageClass.thisType, cls, List(ObjectClass.typeRef), paramDecls)
467+
newTypeParam(cls, tpnme.lambdaArgName(i), varianceFlags(vcs(i)), paramDecls)
468+
newTypeField(cls, tpnme.Apply, Covariant, paramDecls)
469+
val parentTraitRefs =
470+
for (i <- 0 until vcs.length if vcs(i) != 0)
471+
yield lambdaTrait(vcs.updated(i, 0)).typeRef
472+
denot.info = ClassInfo(
473+
ScalaPackageClass.thisType, cls, ObjectClass.typeRef :: parentTraitRefs.toList, paramDecls)
461474
}
462475
}
463476

464-
val traitName = tpnme.higherKindedTraitName(vcs)
477+
val traitName = tpnme.lambdaTraitName(vcs)
465478

466479
def createTrait = {
467480
val cls = newClassSymbol(
468481
ScalaPackageClass,
469482
traitName,
470483
Trait | Interface | Synthetic,
471484
completer)
472-
_hkTraits += cls
485+
myLambdaTraits += cls
473486
cls
474487
}
475488

476-
hkTraitOfArity.getOrElseUpdate(vcs, createTrait)
489+
lambdaTraitForVariances.getOrElseUpdate(vcs, createTrait)
477490
}
478491

479492
// ----- primitive value class machinery ------------------------------------------

src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ object Denotations {
378378
case info: SignedType =>
379379
try info.signature
380380
catch { // !!! DEBUG
381-
case ex: MatchError =>
381+
case ex: Throwable =>
382382
println(s"cannot take signature of ${info.show}")
383383
throw ex
384384
}

src/dotty/tools/dotc/core/Flags.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,9 @@ object Flags {
198198
final val Final = commonFlag(6, "final")
199199

200200
/** A method symbol. */
201-
final val MethodCommon = commonFlag(7, "<method>")
202-
final val Method = MethodCommon.toTermFlags
201+
final val MethodOrHKCommon = commonFlag(7, "<method>")
202+
final val Method = MethodOrHKCommon.toTermFlags
203+
final val HigherKinded = MethodOrHKCommon.toTypeFlags
203204

204205
/** A (term or type) parameter to a class or method */
205206
final val Param = commonFlag(8, "<param>")
@@ -411,7 +412,7 @@ object Flags {
411412

412413
/** Flags guaranteed to be set upon symbol creation */
413414
final val FromStartFlags =
414-
AccessFlags | Module | Package | Deferred | MethodCommon | Param | Scala2ExistentialCommon | Touched |
415+
AccessFlags | Module | Package | Deferred | MethodOrHKCommon | Param | Scala2ExistentialCommon | Touched |
415416
Static | CovariantCommon | ContravariantCommon | ExpandedName | AccessorOrSealed |
416417
CaseAccessorOrTypeArgument | Frozen | Erroneous | ImplicitCommon | Permanent | SelfNameOrImplClass
417418

src/dotty/tools/dotc/core/Hashable.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ trait Hashable {
3333
private def finishHash(hashCode: Int, arity: Int): Int =
3434
avoidNotCached(hashing.finalizeHash(hashCode, arity))
3535

36-
protected final def identityHash = avoidNotCached(System.identityHashCode(this))
36+
final def identityHash = avoidNotCached(System.identityHashCode(this))
3737

3838
private def finishHash(seed: Int, arity: Int, tp: Type): Int = {
3939
val elemHash = tp.hash

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

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ object NameOps {
6666
def isSingletonName = name endsWith SINGLETON_SUFFIX
6767
def isModuleClassName = name endsWith MODULE_SUFFIX
6868
def isImportName = name startsWith IMPORT
69-
def isInheritedName = name.head == '(' && name.startsWith(nme.INHERITED)
69+
def isInheritedName = name.length > 0 && name.head == '(' && name.startsWith(nme.INHERITED)
7070

7171
def isModuleVarName(name: Name): Boolean =
7272
name.stripAnonNumberSuffix endsWith MODULE_VAR_SUFFIX
7373

7474
/** Is name a variable name? */
75-
def isVariableName: Boolean = {
75+
def isVariableName: Boolean = name.length > 0 && {
7676
val first = name.head
7777
(((first.isLower && first.isLetter) || first == '_')
7878
&& (name != false_)
@@ -84,16 +84,17 @@ object NameOps {
8484
case raw.NE | raw.LE | raw.GE | EMPTY =>
8585
false
8686
case _ =>
87-
name.last == '=' && name.head != '=' && isOperatorPart(name.head)
87+
name.length > 0 && name.last == '=' && name.head != '=' && isOperatorPart(name.head)
8888
}
8989

90-
/** Is this the name of a higher-kinded type parameter? */
91-
def isHkParamName: Boolean = name(0) == '_' && name.startsWith(HK_PARAM_PREFIX)
90+
/** Is this the name of a higher-kinded type parameter of a Lambda? */
91+
def isLambdaArgName =
92+
name.length > 0 && name.head == tpnme.LAMBDA_ARG_PREFIXhead && name.startsWith(tpnme.LAMBDA_ARG_PREFIX)
9293

9394
/** The index of the higher-kinded type parameter with this name.
94-
* Pre: isHkParamName.
95+
* Pre: isLambdaArgName.
9596
*/
96-
def hkParamIndex: Int = name.drop(name.lastIndexOf('$') + 1).toString.toInt
97+
def lambdaArgIndex: Int = name.drop(name.lastIndexOf('$') + 1).toString.toInt
9798

9899
/** If the name ends with $nn where nn are
99100
* all digits, strip the $ and the digits.
@@ -177,19 +178,6 @@ object NameOps {
177178
}
178179
}
179180

180-
/** The variances of the higherKinded parameters of the trait named
181-
* by this name.
182-
* @pre The name is a higher-kinded trait name, i.e. it starts with HK_TRAIT_PREFIX
183-
*/
184-
def hkVariances: List[Int] = {
185-
def varianceOfSuffix(suffix: Char): Int = {
186-
val idx = tpnme.varianceSuffixes.indexOf(suffix)
187-
assert(idx >= 0)
188-
idx - 1
189-
}
190-
name.drop(tpnme.HK_TRAIT_PREFIX.length).toList.map(varianceOfSuffix)
191-
}
192-
193181
/** The name of the generic runtime operation corresponding to an array operation */
194182
def genericArrayOp: TermName = name match {
195183
case nme.apply => nme.array_apply

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ object StdNames {
166166
final val WILDCARD_STAR: N = "_*"
167167
final val REIFY_TREECREATOR_PREFIX: N = "$treecreator"
168168
final val REIFY_TYPECREATOR_PREFIX: N = "$typecreator"
169+
final val LAMBDA_ARG_PREFIX: N = "$hkArg$"
170+
final val LAMBDA_ARG_PREFIXhead: Char = LAMBDA_ARG_PREFIX.head
169171

170172
final val Any: N = "Any"
171173
final val AnyVal: N = "AnyVal"
@@ -249,8 +251,6 @@ object StdNames {
249251
val SKOLEM: N = "<skolem>"
250252
val SPECIALIZED_INSTANCE: N = "specInstance$"
251253
val THIS: N = "_$this"
252-
val HK_PARAM_PREFIX: N = "_$hk$"
253-
val HK_TRAIT_PREFIX: N = "$HigherKinded$"
254254

255255
final val Nil: N = "Nil"
256256
final val Predef: N = "Predef"
@@ -286,6 +286,7 @@ object StdNames {
286286
val Flag : N = "Flag"
287287
val Ident: N = "Ident"
288288
val Import: N = "Import"
289+
val LambdaPrefix: N = "Lambda$"
289290
val Literal: N = "Literal"
290291
val LiteralAnnotArg: N = "LiteralAnnotArg"
291292
val Modifiers: N = "Modifiers"
@@ -645,8 +646,8 @@ object StdNames {
645646
def syntheticTypeParamNames(num: Int): List[TypeName] =
646647
(0 until num).map(syntheticTypeParamName)(breakOut)
647648

648-
def higherKindedTraitName(vcs: List[Int]): TypeName = HK_TRAIT_PREFIX ++ vcs.map(varianceSuffix).mkString
649-
def higherKindedParamName(n: Int) = HK_PARAM_PREFIX ++ n.toString
649+
def lambdaTraitName(vcs: List[Int]): TypeName = LambdaPrefix ++ vcs.map(varianceSuffix).mkString
650+
def lambdaArgName(n: Int) = LAMBDA_ARG_PREFIX ++ n.toString
650651

651652
final val Conforms = encode("<:<")
652653

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,9 +321,17 @@ object SymDenotations {
321321
final def isAnonymousClass(implicit ctx: Context): Boolean =
322322
initial.asSymDenotation.name startsWith tpnme.ANON_CLASS
323323

324+
/** Is this symbol a class representing a refinement? These classes
325+
* are used only temporarily in Typer and Unpickler as an intermediate
326+
* step for creating Refinement types.
327+
*/
324328
final def isRefinementClass(implicit ctx: Context): Boolean =
325329
name.decode == tpnme.REFINE_CLASS
326330

331+
/** is this symbol a trait representing a type lambda? */
332+
final def isLambdaTrait(implicit ctx: Context): Boolean =
333+
isClass && name.startsWith(tpnme.LambdaPrefix)
334+
327335
/** Is this symbol a package object or its module class? */
328336
def isPackageObject(implicit ctx: Context): Boolean = {
329337
val poName = if (isType) nme.PACKAGE_CLS else nme.PACKAGE
@@ -699,7 +707,7 @@ object SymDenotations {
699707

700708
/** All symbols overriden by this denotation. */
701709
final def allOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] =
702-
if (exists)
710+
if (exists && owner.isClass)
703711
owner.info.baseClasses.tail.iterator map overriddenSymbol filter (_.exists)
704712
else
705713
Iterator.empty

0 commit comments

Comments
 (0)