Skip to content

Add extension clauses #4085

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 50 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
ab9aca1
Add opaque types: parsing & pickling
odersky Feb 21, 2018
5e1b0a8
Store opaque info in annotation
odersky Feb 21, 2018
f5ef7b8
Keep track of opaque companion links
odersky Feb 21, 2018
2403e06
Maintain companion aliases as GADT bounds
odersky Feb 21, 2018
f5060be
Test cases
odersky Feb 21, 2018
b7e7ef7
Allow for higher-kinded opaque types
odersky Feb 21, 2018
a79210b
Handle higher-kinded comparisons involving GADTs
odersky Feb 21, 2018
a11d1ad
Change companion detection scheme
odersky Feb 22, 2018
4feb71d
Eliminate boxing for opaque types
odersky Feb 22, 2018
1f985da
Make OpaqueAlias and LinkedType special classes
odersky Feb 22, 2018
3fb11d2
Make implicit scope include companion objects of opaque types
odersky Feb 22, 2018
f9b141b
Add reference documentation
odersky Feb 22, 2018
599b408
Fix test
odersky Feb 22, 2018
cdc5e54
Fix indentation
odersky Feb 22, 2018
95a3d07
Treat companions of opaque types specially
odersky Feb 23, 2018
1d03fc0
Replace annotation extractor with access methods
odersky Feb 23, 2018
4293432
Simplify companion scheme
odersky Feb 24, 2018
8ac08cc
add test
odersky Feb 24, 2018
c6bb46f
Bump minor Tasty version
odersky Mar 9, 2018
b2e85a0
Follow GADT bounds when computing members
odersky Mar 9, 2018
7b67237
Consider GADT bounds for findMember and underlying
odersky Mar 12, 2018
5de563b
Extend opaque companion context to inlined code
odersky Mar 12, 2018
f6dffe4
Add augment clauses
odersky Feb 26, 2018
971e385
Allow for `type id` in type patterns
odersky Feb 27, 2018
3e55b6b
Convert tests to use new type pattern syntax
odersky Feb 27, 2018
6d2cbba
Base augment syntax on type patterns
odersky Feb 27, 2018
cb5ae51
Fix typo
odersky Feb 27, 2018
dc05718
Make annotation names compilation-order independent
odersky Feb 27, 2018
958e67a
Require that non-extending augments only add extension methods
odersky Feb 27, 2018
f8b661d
Implement extension methods as implicit value classes
odersky Feb 27, 2018
b90acc1
Partially fix idempotency of static method order
nicolasstucki Feb 27, 2018
55405d8
Allow labels naming an augment
odersky Feb 27, 2018
d4f50df
Use semantic names for augmentations
odersky Feb 28, 2018
823ba95
Add regression test for idempotency issue on static methods
nicolasstucki Feb 28, 2018
90ec0ee
Add docs for extension methods
odersky Feb 28, 2018
0b0c2e0
More docs for augmentations
odersky Feb 28, 2018
5297996
Remove duplicate test
odersky Mar 1, 2018
1c55e04
Fix typos
odersky Mar 7, 2018
1e4b2a1
Change syntax from augment/extends to extend/implements
odersky Mar 8, 2018
ff65a2b
Fix test and error reporting
odersky Mar 8, 2018
53298ce
Require implemented types to be traits
odersky Mar 8, 2018
19d12d9
Another test - magnet pattern
odersky Mar 8, 2018
f8bd21a
Change syntax of instance declarations
odersky Mar 9, 2018
b757ba9
A blue sky sketch how one could possibly evolve extends clauses
odersky Mar 9, 2018
23c863e
Fix test
odersky Mar 9, 2018
420a79d
Fix typos
odersky Mar 9, 2018
09aa5d2
More blue sky variants
odersky Mar 11, 2018
51bff8d
Some small updates and variants to blySkyExtensions
odersky Mar 14, 2018
cfc9058
Relax restriction about type overrides
odersky Mar 14, 2018
f65f8b3
More escaping of "extension"
odersky Mar 15, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 155 additions & 15 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ package ast

import core._
import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._
import util.Chars.isIdentifierPart
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._
import Decorators._, transform.SymUtils._
import NameKinds.{UniqueName, EvidenceParamName, DefaultGetterName}
import language.higherKinds
import typer.FrontEnd
import collection.mutable.ListBuffer
import util.Property
import config.Printers.desugr
import reporting.diagnostic.messages._
import reporting.trace

Expand Down Expand Up @@ -154,6 +156,25 @@ object desugar {
ValDef(epname, tpt, EmptyTree).withFlags(paramFlags | Implicit)
}

private def desugarTypeBindings(
bindings: List[TypeDef],
forPrimaryConstructor: Boolean = false)(implicit ctx: Context): (List[TypeDef], List[ValDef]) = {
val epbuf = new ListBuffer[ValDef]
def desugarContextBounds(rhs: Tree): Tree = rhs match {
case ContextBounds(tbounds, cxbounds) =>
epbuf ++= makeImplicitParameters(cxbounds, forPrimaryConstructor)
tbounds
case LambdaTypeTree(tparams, body) =>
cpy.LambdaTypeTree(rhs)(tparams, desugarContextBounds(body))
case _ =>
rhs
}
val bindings1 = bindings mapConserve { tparam =>
cpy.TypeDef(tparam)(rhs = desugarContextBounds(tparam.rhs))
}
(bindings1, epbuf.toList)
}

/** Expand context bounds to evidence params. E.g.,
*
* def f[T >: L <: H : B](params)
Expand All @@ -171,21 +192,8 @@ object desugar {
private def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false)(implicit ctx: Context): Tree = {
val DefDef(name, tparams, vparamss, tpt, rhs) = meth
val mods = meth.mods
val epbuf = new ListBuffer[ValDef]
def desugarContextBounds(rhs: Tree): Tree = rhs match {
case ContextBounds(tbounds, cxbounds) =>
epbuf ++= makeImplicitParameters(cxbounds, isPrimaryConstructor)
tbounds
case LambdaTypeTree(tparams, body) =>
cpy.LambdaTypeTree(rhs)(tparams, desugarContextBounds(body))
case _ =>
rhs
}
val tparams1 = tparams mapConserve { tparam =>
cpy.TypeDef(tparam)(rhs = desugarContextBounds(tparam.rhs))
}

val meth1 = addEvidenceParams(cpy.DefDef(meth)(tparams = tparams1), epbuf.toList)
val (tparams1, evidenceParams) = desugarTypeBindings(tparams, isPrimaryConstructor)
val meth1 = addEvidenceParams(cpy.DefDef(meth)(tparams = tparams1), evidenceParams)

/** The longest prefix of parameter lists in vparamss whose total length does not exceed `n` */
def takeUpTo(vparamss: List[List[ValDef]], n: Int): List[List[ValDef]] = vparamss match {
Expand Down Expand Up @@ -293,6 +301,7 @@ object desugar {
def isAnyVal(tree: Tree): Boolean = tree match {
case Ident(tpnme.AnyVal) => true
case Select(qual, tpnme.AnyVal) => isScala(qual)
case TypedSplice(tree) => tree.tpe.isRef(defn.AnyValClass)
case _ => false
}
def isScala(tree: Tree): Boolean = tree match {
Expand Down Expand Up @@ -749,6 +758,136 @@ object desugar {
Bind(name, Ident(nme.WILDCARD)).withPos(tree.pos)
}

def decomposeTypePattern(tree: Tree)(implicit ctx: Context): (Tree, List[TypeDef]) = {
val bindingsBuf = new ListBuffer[TypeDef]
val elimTypeDefs = new untpd.UntypedTreeMap {
override def transform(tree: Tree)(implicit ctx: Context) = tree match {
case tree: TypeDef =>
bindingsBuf += tree
Ident(tree.name).withPos(tree.pos)
case _ =>
super.transform(tree)
}
}
(elimTypeDefs.transform(tree), bindingsBuf.toList)
}

private val collectNames = new untpd.UntypedTreeAccumulator[ListBuffer[String]] {
def add(buf: ListBuffer[String], name: Name): ListBuffer[String] = {
val alpha = name.toString.filter(isIdentifierPart)
if (alpha.isEmpty) buf else buf += alpha
}
override def apply(buf: ListBuffer[String], tree: Tree)(implicit ctx: Context): ListBuffer[String] = tree match {
case Ident(name) =>
add(buf, name)
case Select(qual, name) =>
add(apply(buf, qual), name)
case TypeDef(name, rhs) =>
apply(add(buf += "type", name), rhs)
case Apply(fn, _) =>
apply(buf, fn)
case _ =>
foldOver(buf, tree)
}
}

private def extensionName(ext: Extension)(implicit ctx: Context): TypeName = {
var buf = collectNames(new ListBuffer[String] += "extend", ext.extended)
if (ext.impl.parents.nonEmpty)
buf = collectNames(buf += "", ext.impl.parents)
buf.toList.mkString("_").toTypeName
}

/** extend <type-pattern> <params> : <parents> { <body>} }
* ->
* implicit class <extension-name> <type-params> ($this: <extended>) <combined-params>
* extends <parents> { <body1> }
*
* where
*
* <extension-name> = concatenation of all alphanumeric characters between and including `extend` and `{`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's consider the impact on binary compatibility. Are there valid changes to the signature, which result in a new name, but which should not affect binary compatibility? Generally, I think it's important to give the programmer the ability to specify a name explicitly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One easy example: exchange a fully-qualified for a relative name or vice versa.

augment List[String] {

would be binary-incompatible with

augment List[java.lang.String] {

under Martin's naming proposal.

Also, renaming a type T parameter into type U.

Plenty more like that.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use fully qualified names & a positional naming scheme for type params?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that would not be what we want. We want variation, in particular in type parameter names, so that we can avoid double definitions.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I think what I meant to say was type patterns? The type T and type U that @sjrd mentioned above. I think you already have a double definition if you have an extension for type T and type U that share the same method name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you already have a double definition if you have an extension for type T and type U that share the same method name.

No that's precisely it - you want to enable multiple extends of the same type. So you should not get a double definition if you change the parameter type.

* mapping every sequence of other characters to a single `_`.
*
* (<decorated>, <type-params0>) = decomposeTypePattern(<type-pattern>)
* (<type-params>, <evidence-params>) = desugarTypeBindings(<type-params0>)
* <combined-params> = <params> concatenated with <evidence-params> in one clause
* <body1> = <body> with each occurrence of unqualified `this` substituted by `$this`.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* extend <type-pattern> <params> { <body> }
* ->
* implicit class <extension-name> <type-params> ($this: <extended>)
* extends AnyVal { <body2> }
*
* where
*
* <body2> = <body1> where each method definition gets <combined-params> as last parameter section.
* <extenion-name>, <type-params> are as above.
*/
def extension(tree: Extension)(implicit ctx: Context): Tree = {
val Extension(extended, impl) = tree
val isSimpleExtension = impl.parents.isEmpty
val (decorated, bindings) = decomposeTypePattern(extended)
val (typeParams, evidenceParams) =
desugarTypeBindings(bindings, forPrimaryConstructor = !isSimpleExtension)
val extName = extensionName(tree)

val firstParam = ValDef(nme.SELF, decorated, EmptyTree).withFlags(Private | Local | ParamAccessor)
var constr1 =
cpy.DefDef(impl.constr)(
tparams = typeParams.map(_.withFlags(Param | Private | Local)),
vparamss = (firstParam :: Nil) :: impl.constr.vparamss)
var parents1 = impl.parents
var body1 = substThis.transform(impl.body)
if (isSimpleExtension) {
constr1 = cpy.DefDef(constr1)(vparamss = constr1.vparamss.take(1))
parents1 = ref(defn.AnyValType) :: Nil
body1 = body1.map {
case ddef: DefDef =>
def resetFlags(vdef: ValDef) =
vdef.withMods(vdef.mods &~ PrivateLocalParamAccessor | Param)
val originalParams = impl.constr.vparamss.headOption.getOrElse(Nil).map(resetFlags)
addEvidenceParams(addEvidenceParams(ddef, originalParams), evidenceParams)
case other =>
other
}
}
else
constr1 = addEvidenceParams(constr1, evidenceParams)

val mods =
if (isSimpleExtension) EmptyModifiers
else EmptyModifiers.withAddedMod(Mod.InstanceDecl())
val icls =
TypeDef(extName,
cpy.Template(impl)(constr = constr1, parents = parents1, body = body1))
.withMods(mods.withFlags(Implicit))
desugr.println(i"desugar $extended --> $icls")
classDef(icls)
}

private val substThis = new UntypedTreeMap {
override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match {
case This(Ident(tpnme.EMPTY)) => Ident(nme.SELF).withPos(tree.pos)
case _ => super.transform(tree)
}
}

private val leadingName = new UntypedTreeAccumulator[String] {
override def apply(x: String, tree: Tree)(implicit ctx: Context): String =
if (x.isEmpty)
tree match {
case Select(pre, nme.CONSTRUCTOR) => foldOver(x, pre)
case tree: RefTree if tree.name.isTypeName => tree.name.toString
case tree: TypeDef => tree.name.toString
case tree: Tuple => "Tuple"
case tree: Function => "Function"
case _ => foldOver(x, tree)
}
else x
}

def defTree(tree: Tree)(implicit ctx: Context): Tree = tree match {
case tree: ValDef => valDef(tree)
case tree: TypeDef => if (tree.isClassDef) classDef(tree) else tree
Expand All @@ -757,6 +896,7 @@ object desugar {
else defDef(tree)
case tree: ModuleDef => moduleDef(tree)
case tree: PatDef => patDef(tree)
case tree: Extension => extension(tree)
}

/** { stats; <empty > }
Expand Down
7 changes: 5 additions & 2 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1017,8 +1017,11 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
/** A key to be used in a context property that tracks enclosing inlined calls */
private val InlinedCalls = new Property.Key[List[Tree]]

override def inlineContext(call: Tree)(implicit ctx: Context): Context =
ctx.fresh.setProperty(InlinedCalls, call :: enclosingInlineds)
override def inlineContext(call: Tree)(implicit ctx: Context): Context = {
val ictx = ctx.fresh.setProperty(InlinedCalls, call :: enclosingInlineds)
def stopAt(owner: Symbol) = owner.is(Package) || ctx.owner.isContainedIn(owner)
(ictx /: call.symbol.ownersIterator.takeWhile(!stopAt(_)))(ctx.handleOpaqueCompanion)
}

/** All enclosing calls that are currently inlined, from innermost to outermost */
def enclosingInlineds(implicit ctx: Context): List[Tree] =
Expand Down
11 changes: 11 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def withName(name: Name)(implicit ctx: Context) = cpy.ModuleDef(this)(name.toTermName, impl)
}

/** extend extended impl */
case class Extension(extended: Tree, impl: Template) extends DefTree

case class ParsedTry(expr: Tree, handler: Tree, finalizer: Tree) extends TermTree

case class SymbolLit(str: String) extends TermTree
Expand Down Expand Up @@ -124,6 +127,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {

case class Sealed() extends Mod(Flags.Sealed)

case class Opaque() extends Mod(Flags.Opaque)

case class Override() extends Mod(Flags.Override)

case class Abstract() extends Mod(Flags.Abstract)
Expand All @@ -137,6 +142,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
case class Enum() extends Mod(Flags.EmptyFlags)

case class EnumCase() extends Mod(Flags.EmptyFlags)

case class InstanceDecl() extends Mod(Flags.EmptyFlags)
}

/** Modifiers and annotations for definitions
Expand Down Expand Up @@ -409,6 +416,10 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
case tree: ModuleDef if (name eq tree.name) && (impl eq tree.impl) => tree
case _ => finalize(tree, untpd.ModuleDef(name, impl))
}
def Extension(tree: Tree)(extended: Tree, impl: Template) = tree match {
case tree: Extension if (extended eq tree.extended) && (impl eq tree.impl) => tree
case _ => finalize(tree, untpd.Extension(extended, impl))
}
def ParsedTry(tree: Tree)(expr: Tree, handler: Tree, finalizer: Tree) = tree match {
case tree: ParsedTry
if (expr eq tree.expr) && (handler eq tree.handler) && (finalizer eq tree.finalizer) => tree
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/config/Printers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ object Printers {
val checks: Printer = noPrinter
val config: Printer = noPrinter
val cyclicErrors: Printer = noPrinter
val desugr: Printer = noPrinter
val dottydoc: Printer = noPrinter
val exhaustivity: Printer = noPrinter
val gadts: Printer = noPrinter
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ class Definitions {
lazy val EqualsPatternClass = enterSpecialPolyClass(tpnme.EQUALS_PATTERN, EmptyFlags, Seq(AnyType))

lazy val RepeatedParamClass = enterSpecialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, Seq(ObjectType, SeqType))
lazy val OpaqueAliasAnnot = enterSpecialPolyClass(tpnme.OPAQUE_ALIAS, EmptyFlags, Seq(AnyType))

// fundamental classes
lazy val StringClass = ctx.requiredClass("java.lang.String")
Expand Down Expand Up @@ -1154,6 +1155,7 @@ class Definitions {
AnyRefAlias,
RepeatedParamClass,
ByNameParamClass2x,
OpaqueAliasAnnot,
AnyValClass,
NullClass,
NothingClass,
Expand Down
17 changes: 11 additions & 6 deletions compiler/src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,14 @@ object Flags {

final val AccessorOrSealed = Accessor.toCommonFlags

/** A mutable var */
/** A mutable var */
final val Mutable = termFlag(12, "mutable")

/** An opqaue type */
final val Opaque = typeFlag(12, "opaque")

final val MutableOrOpaque = Mutable.toCommonFlags

/** Symbol is local to current class (i.e. private[this] or protected[this]
* pre: Private or Protected are also set
*/
Expand All @@ -264,7 +269,7 @@ object Flags {
*/
final val ParamAccessor = termFlag(14, "<paramaccessor>")

/** A value or class implementing a module */
/** A value or class implementing a module */
final val Module = commonFlag(15, "module")
final val ModuleVal = Module.toTermFlags
final val ModuleClass = Module.toTypeFlags
Expand Down Expand Up @@ -441,12 +446,12 @@ object Flags {
/** Flags representing source modifiers */
final val SourceModifierFlags =
commonFlags(Private, Protected, Abstract, Final, Inline,
Sealed, Case, Implicit, Override, AbsOverride, Lazy, JavaStatic, Erased)
Sealed, Case, Implicit, Override, AbsOverride, Lazy, JavaStatic, Erased, Opaque)

/** Flags representing modifiers that can appear in trees */
final val ModifierFlags =
SourceModifierFlags | Module | Param | Synthetic | Package | Local |
commonFlags(Mutable)
SourceModifierFlags | Module | Param | Synthetic | Package | Local
// | Mutable is subsumed by commonFlags(Opaque) from SourceModifierFlags
// | Trait is subsumed by commonFlags(Lazy) from SourceModifierFlags

assert(ModifierFlags.isTermFlags && ModifierFlags.isTypeFlags)
Expand All @@ -457,7 +462,7 @@ object Flags {
/** Flags guaranteed to be set upon symbol creation */
final val FromStartFlags =
Module | Package | Deferred | MethodOrHKCommon | Param | ParamAccessor.toCommonFlags |
Scala2ExistentialCommon | Mutable.toCommonFlags | Touched | JavaStatic |
Scala2ExistentialCommon | MutableOrOpaque | Touched | JavaStatic |
CovariantOrOuter | ContravariantOrLabel | CaseAccessor.toCommonFlags |
NonMember | Erroneous | ImplicitCommon | Permanent | Synthetic |
SuperAccessorOrScala2x | Inline
Expand Down
16 changes: 3 additions & 13 deletions compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,6 @@ object StdNames {
val WHILE_PREFIX: N = "while$"
val DEFAULT_EXCEPTION_NAME: N = "ex$"
val INITIALIZER_PREFIX: N = "initial$"
val COMPANION_MODULE_METHOD: N = "companion$module"
val COMPANION_CLASS_METHOD: N = "companion$class"
val BOUNDTYPE_ANNOT: N = "$boundType$"
val QUOTE: N = "'"
val TYPE_QUOTE: N = "type_'"
Expand Down Expand Up @@ -191,6 +189,8 @@ object StdNames {
final val EQUALS_PATTERN: N = "<equals>"
final val LOCAL_CHILD: N = "<local child>"
final val REPEATED_PARAM_CLASS: N = "<repeated>"
final val OPAQUE_ALIAS: N = "<opaque>"
final val LINKED_TYPE: N = "<linked-type>"
final val WILDCARD_STAR: N = "_*"
final val REIFY_TREECREATOR_PREFIX: N = "$treecreator"
final val REIFY_TYPECREATOR_PREFIX: N = "$typecreator"
Expand Down Expand Up @@ -246,6 +246,7 @@ object StdNames {

// Compiler-internal
val ANYname: N = "<anyname>"
val COMPANION: N = "<companion>"
val CONSTRUCTOR: N = "<init>"
val STATIC_CONSTRUCTOR: N = "<clinit>"
val DEFAULT_CASE: N = "defaultCase$"
Expand All @@ -254,17 +255,6 @@ object StdNames {
val FAKE_LOCAL_THIS: N = "this$"
val LAZY_FIELD_OFFSET: N = "OFFSET$"
val LAZY_SLOW_SUFFIX: N = "$lzycompute"
val UNIVERSE_BUILD_PREFIX: N = "$u.build."
val UNIVERSE_BUILD: N = "$u.build"
val UNIVERSE_PREFIX: N = "$u."
val UNIVERSE_SHORT: N = "$u"
val MIRROR_PREFIX: N = "$m."
val MIRROR_SHORT: N = "$m"
val MIRROR_UNTYPED: N = "$m$untyped"
val REIFY_FREE_PREFIX: N = "free$"
val REIFY_FREE_THIS_SUFFIX: N = "$this"
val REIFY_FREE_VALUE_SUFFIX: N = "$value"
val REIFY_SYMDEF_PREFIX: N = "symdef$"
val OUTER: N = "$outer"
val REFINE_CLASS: N = "<refinement>"
val ROOTPKG: N = "_root_"
Expand Down
Loading