diff options
Diffstat (limited to 'src')
10 files changed, 149 insertions, 62 deletions
diff --git a/src/compiler/scala/reflect/reify/package.scala b/src/compiler/scala/reflect/reify/package.scala index 2600956805..5a23ab7214 100644 --- a/src/compiler/scala/reflect/reify/package.scala +++ b/src/compiler/scala/reflect/reify/package.scala @@ -72,7 +72,7 @@ package object reify { def reifyEnclosingRuntimeClass(global: Global)(typer0: global.analyzer.Typer): global.Tree = { import global._ import definitions._ - def isThisInScope = typer0.context.enclosingContextChain exists (_.tree.isInstanceOf[Template]) + def isThisInScope = typer0.context.enclosingContextChain exists (_.tree.isInstanceOf[ImplDef]) if (isThisInScope) { val enclosingClasses = typer0.context.enclosingContextChain map (_.tree) collect { case classDef: ClassDef => classDef } val classInScope = enclosingClasses.headOption getOrElse EmptyTree diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 6fb6b1736b..58fcee4b30 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1094,6 +1094,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) // TODO - trim these to the absolute minimum. @inline final def afterErasure[T](op: => T): T = afterPhase(currentRun.erasurePhase)(op) + @inline final def afterPostErasure[T](op: => T): T = afterPhase(currentRun.posterasurePhase)(op) @inline final def afterExplicitOuter[T](op: => T): T = afterPhase(currentRun.explicitouterPhase)(op) @inline final def afterFlatten[T](op: => T): T = afterPhase(currentRun.flattenPhase)(op) @inline final def afterIcode[T](op: => T): T = afterPhase(currentRun.icodePhase)(op) @@ -1403,6 +1404,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val specializePhase = phaseNamed("specialize") val explicitouterPhase = phaseNamed("explicitouter") val erasurePhase = phaseNamed("erasure") + val posterasurePhase = phaseNamed("posterasure") // val lazyvalsPhase = phaseNamed("lazyvals") val lambdaliftPhase = phaseNamed("lambdalift") // val constructorsPhase = phaseNamed("constructors") diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index b3b0c82d38..072d823c60 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -167,6 +167,8 @@ abstract class Erasure extends AddInterfaces case tp => tp :: Nil } + private def isErasedValueType(tpe: Type) = tpe.isInstanceOf[ErasedValueType] + /** The Java signature of type 'info', for symbol sym. The symbol is used to give the right return * type for constructors. */ @@ -373,18 +375,18 @@ abstract class Erasure extends AddInterfaces } } - class ComputeBridges(owner: Symbol) { + class ComputeBridges(unit: CompilationUnit, root: Symbol) { assert(phase == currentRun.erasurePhase, phase) var toBeRemoved = immutable.Set[Symbol]() - val site = owner.thisType + val site = root.thisType val bridgesScope = newScope val bridgeTarget = mutable.HashMap[Symbol, Symbol]() var bridges = List[Tree]() val opc = beforeExplicitOuter { - new overridingPairs.Cursor(owner) { - override def parents = List(owner.info.firstParent) + new overridingPairs.Cursor(root) { + override def parents = List(root.info.firstParent) override def exclude(sym: Symbol) = !sym.isMethod || sym.isPrivate || super.exclude(sym) } } @@ -402,8 +404,58 @@ abstract class Erasure extends AddInterfaces (bridges, toBeRemoved) } + /** Check that a bridge only overrides members that are also overridden by the original member. + * This test is necessary only for members that have a value class in their type. + * Such members are special because their types after erasure and after post-erasure differ/. + * This means we generate them after erasure, but the post-erasure transform might introduce + * a name clash. The present method guards against these name clashes. + * + * @param member The original member + * @param other The overidden symbol for which the bridge was generated + * @param bridge The bridge + */ + def checkBridgeOverrides(member: Symbol, other: Symbol, bridge: Symbol): Boolean = { + def fulldef(sym: Symbol) = + if (sym == NoSymbol) sym.toString + else s"$sym: ${sym.tpe} in ${sym.owner}" + var noclash = true + def clashError(what: String) = { + noclash = false + unit.error( + if (member.owner == root) member.pos else root.pos, + s"""bridge generated for member ${fulldef(member)} + |which overrides ${fulldef(other)} + |clashes with definition of $what; + |both have erased type ${afterPostErasure(bridge.tpe)}""".stripMargin) + } + for (bc <- root.baseClasses) { + if (settings.debug.value) + afterPostErasure(println( + s"""check bridge overrides in $bc + ${bc.info.nonPrivateDecl(bridge.name)} + ${site.memberType(bridge)} + ${site.memberType(bc.info.nonPrivateDecl(bridge.name) orElse IntClass)} + ${(bridge.matchingSymbol(bc, site))}""".stripMargin)) + + def overriddenBy(sym: Symbol) = + sym.matchingSymbol(bc, site).alternatives filter (sym => !sym.isBridge) + for (overBridge <- afterPostErasure(overriddenBy(bridge))) { + if (overBridge == member) { + clashError("the member itself") + } else { + val overMembers = overriddenBy(member) + if (!overMembers.exists(overMember => + afterPostErasure(overMember.tpe =:= overBridge.tpe))) { + clashError(fulldef(overBridge)) + } + } + } + } + noclash + } + def checkPair(member: Symbol, other: Symbol) { - val otpe = erasure(owner)(other.tpe) + val otpe = erasure(root)(other.tpe) val bridgeNeeded = afterErasure ( !(other.tpe =:= member.tpe) && !(deconstMap(other.tpe) =:= deconstMap(member.tpe)) && @@ -417,24 +469,29 @@ abstract class Erasure extends AddInterfaces return val newFlags = (member.flags | BRIDGE) & ~(ACCESSOR | DEFERRED | LAZY | lateDEFERRED) - val bridge = other.cloneSymbolImpl(owner, newFlags) setPos owner.pos + val bridge = other.cloneSymbolImpl(root, newFlags) setPos root.pos debuglog("generating bridge from %s (%s): %s to %s: %s".format( other, flagsToString(newFlags), otpe + other.locationString, member, - erasure(owner)(member.tpe) + member.locationString) + erasure(root)(member.tpe) + member.locationString) ) // the parameter symbols need to have the new owner bridge setInfo (otpe cloneInfo bridge) bridgeTarget(bridge) = member - afterErasure(owner.info.decls enter bridge) - if (other.owner == owner) { - afterErasure(owner.info.decls.unlink(other)) - toBeRemoved += other + + if (!(member.tpe exists (_.typeSymbol.isDerivedValueClass)) || + checkBridgeOverrides(member, other, bridge)) { + afterErasure(root.info.decls enter bridge) + if (other.owner == root) { + afterErasure(root.info.decls.unlink(other)) + toBeRemoved += other + } + + bridgesScope enter bridge + bridges ::= makeBridgeDefDef(bridge, member, other) } - bridgesScope enter bridge - bridges ::= makeBridgeDefDef(bridge, member, other) } def makeBridgeDefDef(bridge: Symbol, member: Symbol, other: Symbol) = afterErasure { @@ -466,7 +523,7 @@ abstract class Erasure extends AddInterfaces val rhs = member.tpe match { case MethodType(Nil, ConstantType(c)) => Literal(c) case _ => - val sel: Tree = Select(This(owner), member) + val sel: Tree = Select(This(root), member) val bridgingCall = (sel /: bridge.paramss)((fun, vparams) => Apply(fun, vparams map Ident)) maybeWrap(bridgingCall) @@ -480,8 +537,6 @@ abstract class Erasure extends AddInterfaces private def isPrimitiveValueType(tpe: Type) = isPrimitiveValueClass(tpe.typeSymbol) - private def isErasedValueType(tpe: Type) = tpe.isInstanceOf[ErasedValueType] - private def isDifferentErasedValueType(tpe: Type, other: Type) = isErasedValueType(tpe) && (tpe ne other) @@ -814,7 +869,6 @@ abstract class Erasure extends AddInterfaces * but their erased types are the same. */ private def checkNoDoubleDefs(root: Symbol) { - def afterErasure[T](op: => T): T = atPhase(phase.next.next)(op) def doubleDefError(sym1: Symbol, sym2: Symbol) { // the .toString must also be computed at the earlier phase val tpe1 = afterRefchecks(root.thisType.memberType(sym1)) @@ -830,7 +884,7 @@ abstract class Erasure extends AddInterfaces sym2 + ":" + afterRefchecks(tpe2.toString) + (if (sym2.owner == root) " at line " + (sym2.pos).line else sym2.locationString) + "\nhave same type" + - (if (afterRefchecks(tpe1 =:= tpe2)) "" else " after erasure: " + afterErasure(sym1.tpe))) + (if (afterRefchecks(tpe1 =:= tpe2)) "" else " after erasure: " + afterPostErasure(sym1.tpe))) sym1.setInfo(ErrorType) } @@ -840,7 +894,7 @@ abstract class Erasure extends AddInterfaces if (e.sym.isTerm) { var e1 = decls.lookupNextEntry(e) while (e1 ne null) { - if (afterErasure(e1.sym.info =:= e.sym.info)) doubleDefError(e.sym, e1.sym) + if (afterPostErasure(e1.sym.info =:= e.sym.info)) doubleDefError(e.sym, e1.sym) e1 = decls.lookupNextEntry(e1) } } @@ -854,7 +908,7 @@ abstract class Erasure extends AddInterfaces || !sym.hasTypeAt(currentRun.refchecksPhase.id)) override def matches(sym1: Symbol, sym2: Symbol): Boolean = - afterErasure(sym1.tpe =:= sym2.tpe) + afterPostErasure(sym1.tpe =:= sym2.tpe) } while (opc.hasNext) { if (!afterRefchecks( @@ -902,7 +956,7 @@ abstract class Erasure extends AddInterfaces private def bridgeDefs(owner: Symbol): (List[Tree], immutable.Set[Symbol]) = { assert(phase == currentRun.erasurePhase, phase) debuglog("computing bridges for " + owner) - new ComputeBridges(owner) compute() + new ComputeBridges(unit, owner) compute() } def addBridges(stats: List[Tree], base: Symbol): List[Tree] = @@ -1000,7 +1054,7 @@ abstract class Erasure extends AddInterfaces preEraseIsInstanceOf } else if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) { ApplyDynamic(qualifier, args) setSymbol fn.symbol setPos tree.pos - } else if (fn.symbol.isMethodWithExtension) { + } else if (fn.symbol.isMethodWithExtension && !fn.symbol.tpe.isErroneous) { Apply(gen.mkAttributedRef(extensionMethods.extensionMethod(fn.symbol)), qualifier :: args) } else { tree diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index 0820d3e714..c72fd3681f 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -70,7 +70,8 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { val companionInfo = imeth.owner.companionModule.info val candidates = extensionNames(imeth) map (companionInfo.decl(_)) val matching = candidates filter (alt => normalize(alt.tpe, imeth.owner) matches imeth.tpe) - assert(matching.nonEmpty, "no extension method found for "+imeth+" among "+candidates+"/"+extensionNames(imeth)) + assert(matching.nonEmpty, + s"no extension method found for $imeth:${imeth.tpe}+among ${candidates map (c => c.name+":"+c.tpe)} / ${extensionNames(imeth)}") matching.head } diff --git a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala index f9d8d19b10..0b58292f28 100644 --- a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala +++ b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala @@ -104,8 +104,11 @@ abstract class OverridingPairs { /** A map from baseclasses of <base> to ints, with smaller ints meaning lower in * linearization order. + * symbols that are not baseclasses map to -1. */ - private val index = new mutable.HashMap[Symbol, Int] + private val index = new mutable.HashMap[Symbol, Int] { + override def default(key: Symbol) = -1 + } // Note: overridingPairs can be called at odd instances by the Eclipse plugin // Soemtimes symbols are not yet defined and we get missing keys. @@ -133,28 +136,30 @@ abstract class OverridingPairs { { for (i <- List.range(0, size)) subParents(i) = new BitSet(size); for (p <- parents) { - index get p.typeSymbol match { - case Some(pIndex) => - for (bc <- p.baseClasses) - if (p.baseType(bc) =:= self.baseType(bc)) - index get bc match { - case Some(bcIndex) => - include(subParents(bcIndex), pIndex) - case None => - } - else debuglog("SKIPPING "+p+" -> "+p.baseType(bc)+" / "+self.baseType(bc)+" from "+base) - case None => - } + val pIndex = index(p.typeSymbol) + if (pIndex >= 0) + for (bc <- p.baseClasses) + if (p.baseType(bc) =:= self.baseType(bc)) { + val bcIndex = index(bc) + if (bcIndex >= 0) + include(subParents(bcIndex), pIndex) + } } } /** Do `sym1` and `sym2` have a common subclass in `parents`? * In that case we do not follow their overriding pairs */ - private def hasCommonParentAsSubclass(sym1: Symbol, sym2: Symbol) = ( - for (index1 <- index get sym1.owner ; index2 <- index get sym2.owner) yield - intersectionContainsElementLeq(subParents(index1), subParents(index2), index1 min index2) - ).exists(_ == true) + private def hasCommonParentAsSubclass(sym1: Symbol, sym2: Symbol) = { + val index1 = index(sym1.owner) + (index1 >= 0) && { + val index2 = index(sym2.owner) + (index2 >= 0) && { + intersectionContainsElementLeq( + subParents(index1), subParents(index2), index1 min index2) + } + } + } /** The scope entries that have already been visited as overridden * (maybe excluded because of hasCommonParentAsSubclass). diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 9adf86e44b..f9a35ba9a0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -710,7 +710,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { if (isNullaryInvocation(expandee)) expectedTpe = expectedTpe.finalResultType var typechecked = typecheck("macro def return type", expanded, expectedTpe) typechecked = typecheck("expected type", typechecked, pt) - typechecked updateAttachment MacroExpansionAttachment(expandee) + typechecked } finally { popMacroContext() } @@ -776,7 +776,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { macroLogLite("" + expanded.tree + "\n" + showRaw(expanded.tree)) val freeSyms = expanded.tree.freeTerms ++ expanded.tree.freeTypes freeSyms foreach (sym => MacroFreeSymbolError(expandee, sym)) - Success(atPos(enclosingMacroPosition.focus)(expanded.tree)) + Success(atPos(enclosingMacroPosition.focus)(expanded.tree updateAttachment MacroExpansionAttachment(expandee))) case _ => MacroExpansionIsNotExprError(expandee, expanded) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index ae08a9f64d..9b93c7a214 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1197,7 +1197,7 @@ trait Typers extends Modes with Adaptations with Tags { val found = tree.tpe if (!found.isErroneous && !pt.isErroneous) { - if (!context.reportErrors && isPastTyper) { + if ((!context.reportErrors && isPastTyper) || tree.attachments.get[MacroExpansionAttachment].isDefined) { val (bound, req) = pt match { case ExistentialType(qs, tpe) => (qs, tpe) case _ => (Nil, pt) @@ -1230,6 +1230,17 @@ trait Typers extends Modes with Adaptations with Tags { // to consistently transform skolems and fix 6029), I'd like to // investigate ways to avoid skolems completely. // + // upd. The same problem happens when we try to typecheck the result of macro expansion against its expected type + // (which is the return type of the macro definition instantiated in the context of expandee): + // + // Test.scala:2: error: type mismatch; + // found : $u.Expr[Class[_ <: Object]] + // required: reflect.runtime.universe.Expr[Class[?0(in value <local Test>)]] where type ?0(in value <local Test>) <: Object + // scala.reflect.runtime.universe.reify(new Object().getClass) + // ^ + // Therefore following Martin's advice I use this logic to recover from skolem errors after macro expansions + // (by adding the ` || tree.attachments.get[MacroExpansionAttachment].isDefined` clause to the conditional above). + // log("recovering from existential or skolem type error in tree \n" + tree + "\nwith type " + tree.tpe + "\n expected type = " + pt + "\n context = " + context.tree) return adapt(tree, mode, deriveTypeWithWildcards(boundOrSkolems)(pt)) } diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 27d62e2bac..f985eedf99 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -69,6 +69,14 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => } } + def wrapIntoTerm(tree: Tree): Tree = + if (!tree.isTerm) Block(List(tree), Literal(Constant(()))) else tree + + def unwrapFromTerm(tree: Tree): Tree = tree match { + case Block(List(tree), Literal(Constant(()))) => tree + case tree => tree + } + def extractFreeTerms(expr0: Tree, wrapFreeTermRefs: Boolean): (Tree, scala.collection.mutable.LinkedHashMap[FreeTermSymbol, TermName]) = { val freeTerms = expr0.freeTerms val freeTermNames = scala.collection.mutable.LinkedHashMap[FreeTermSymbol, TermName]() @@ -101,7 +109,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => // need to wrap the expr, because otherwise you won't be able to typecheck macros against something that contains free vars var (expr, freeTerms) = extractFreeTerms(expr0, wrapFreeTermRefs = false) val dummies = freeTerms.map{ case (freeTerm, name) => ValDef(NoMods, name, TypeTree(freeTerm.info), Select(Ident(PredefModule), newTermName("$qmark$qmark$qmark"))) }.toList - expr = Block(dummies, expr) + expr = Block(dummies, wrapIntoTerm(expr)) // [Eugene] how can we implement that? // !!! Why is this is in the empty package? If it's only to make @@ -110,7 +118,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val ownerClass = rootMirror.EmptyPackageClass.newClassSymbol(newTypeName("<expression-owner>")) build.setTypeSignature(ownerClass, ClassInfoType(List(ObjectClass.tpe), newScope, ownerClass)) val owner = ownerClass.newLocalDummy(expr.pos) - var currentTyper = typer.atOwner(expr, owner) + var currentTyper = analyzer.newTyper(analyzer.rootContext(NoCompilationUnit, EmptyTree).make(expr, owner)) val wrapper1 = if (!withImplicitViewsDisabled) (currentTyper.context.withImplicitsEnabled[Tree] _) else (currentTyper.context.withImplicitsDisabled[Tree] _) val wrapper2 = if (!withMacrosDisabled) (currentTyper.context.withMacrosEnabled[Tree] _) else (currentTyper.context.withMacrosDisabled[Tree] _) def wrapper (tree: => Tree) = wrapper1(wrapper2(tree)) @@ -136,6 +144,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => } }.transform(unwrapped) new TreeTypeSubstituter(dummies1 map (_.symbol), dummies1 map (dummy => SingleType(NoPrefix, invertedIndex(dummy.symbol.name)))).traverse(unwrapped) + unwrapped = if (expr0.isTerm) unwrapped else unwrapFromTerm(unwrapped) unwrapped } @@ -169,7 +178,9 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => } }) - def compile(expr: Tree): () => Any = { + def compile(expr0: Tree): () => Any = { + val expr = wrapIntoTerm(expr0) + val freeTerms = expr.freeTerms // need to calculate them here, because later on they will be erased val thunks = freeTerms map (fte => () => fte.value) // need to be lazy in order not to distort evaluation order verify(expr) diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala index cc5b5bb406..977398909f 100644 --- a/src/reflect/scala/reflect/internal/transform/Erasure.scala +++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala @@ -203,28 +203,26 @@ trait Erasure { def specialErasure(sym: Symbol)(tp: Type): Type = if (sym != NoSymbol && sym.enclClass.isJavaDefined) erasure(sym)(tp) - else if (sym.isTerm && sym.owner.isDerivedValueClass) - specialErasureAvoiding(sym.owner, tp) - else if (sym.isValue && sym.owner.isMethodWithExtension) - specialErasureAvoiding(sym.owner.owner, tp) + else if (sym.isClassConstructor) + specialConstructorErasure(sym.owner, tp) else specialScalaErasure(tp) - def specialErasureAvoiding(clazz: Symbol, tpe: Type): Type = { + def specialConstructorErasure(clazz: Symbol, tpe: Type): Type = { tpe match { case PolyType(tparams, restpe) => - specialErasureAvoiding(clazz, restpe) + specialConstructorErasure(clazz, restpe) case ExistentialType(tparams, restpe) => - specialErasureAvoiding(clazz, restpe) + specialConstructorErasure(clazz, restpe) case mt @ MethodType(params, restpe) => MethodType( - cloneSymbolsAndModify(params, specialErasureAvoiding(clazz, _)), - if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass) - else specialErasureAvoiding(clazz, (mt.resultType(mt.paramTypes)))) + cloneSymbolsAndModify(params, specialScalaErasure), + specialConstructorErasure(clazz, restpe)) case TypeRef(pre, `clazz`, args) => typeRef(pre, clazz, List()) - case _ => - specialScalaErasure(tpe) + case tp => + assert(clazz == ArrayClass || tp.isError, s"unexpected constructor erasure $tp for $clazz") + specialScalaErasure(tp) } } diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala index 49c272cc28..a514f0d5a1 100644 --- a/src/scalap/scala/tools/scalap/Main.scala +++ b/src/scalap/scala/tools/scalap/Main.scala @@ -97,9 +97,14 @@ class Main { */ def process(args: Arguments, path: ClassPath[AbstractFile])(classname: String): Unit = { // find the classfile - val encName = NameTransformer.encode( - if (classname == "scala.AnyRef") "java.lang.Object" - else classname) + val encName = classname match { + case "scala.AnyRef" => "java.lang.Object" + case _ => + // we have to encode every fragment of a name separately, otherwise the NameTransformer + // will encode using unicode escaping dot separators as well + // we can afford allocations because this is not a performance critical code + classname.split('.').map(NameTransformer.encode).mkString(".") + } val cls = path.findClass(encName) if (cls.isDefined && cls.get.binary.isDefined) { val cfile = cls.get.binary.get |