From 4e87654a9187fc65e5971580f4e25589fff052b9 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sun, 23 Sep 2012 14:04:40 +0200 Subject: showRaw no longer crashes on NoSymbol --- src/reflect/scala/reflect/internal/Printers.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index cb8dc4b197..fb165ab50f 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -576,7 +576,8 @@ trait Printers extends api.Printers { self: SymbolTable => case _ => // do nothing }) case sym: Symbol => - if (sym.isStatic && (sym.isClass || sym.isModule)) print(sym.fullName) + if (sym == NoSymbol) print("NoSymbol") + else if (sym.isStatic && (sym.isClass || sym.isModule)) print(sym.fullName) else print(sym.name) if (printIds) print("#", sym.id) if (printKinds) print("#", sym.abbreviatedKindString) -- cgit v1.2.3 From a6b81ac12a45866e97d30133c12dee775b93ea39 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sun, 23 Sep 2012 14:07:22 +0200 Subject: SI-6417 correctly reifies non-value types If we're reifying non-value types (e.g. MethodTypes), we can't use them as type arguments for TypeTag/WeakTypeTag factory methods, otherwise the macro expansion won't typecheck: http://groups.google.com/group/scala-internals/browse_thread/thread/2d7bb85bfcdb2e2 This situation is impossible if one uses only reify and type tags, but c.reifyTree and c.reifyType exposes in the macro API let anyone feed anything into the reifier. Therefore I now check the tpe that is about to be used in TypeApply wrapping TypeTag/WeakTypeTag factory methods and replace it with AnyTpe if it doesn't fit. --- .../scala/reflect/reify/utils/Extractors.scala | 14 ++++++++--- test/files/run/macro-reify-type.check | 1 + test/files/run/macro-reify-type.flags | 1 + test/files/run/macro-reify-type/Macros_1.scala | 27 ++++++++++++++++++++++ test/files/run/macro-reify-type/Test_2.scala | 21 +++++++++++++++++ 5 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 test/files/run/macro-reify-type.check create mode 100644 test/files/run/macro-reify-type.flags create mode 100644 test/files/run/macro-reify-type/Macros_1.scala create mode 100644 test/files/run/macro-reify-type/Test_2.scala (limited to 'src') diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala index b7206eda0e..523520749b 100644 --- a/src/compiler/scala/reflect/reify/utils/Extractors.scala +++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala @@ -92,11 +92,19 @@ trait Extractors { Block(List(universeAlias, mirrorAlias), wrappee) } + private def mkTarg(tpe: Type): Tree = { + // if we're reifying a MethodType, we can't use it as a type argument for TypeTag ctor + // http://groups.google.com/group/scala-internals/browse_thread/thread/2d7bb85bfcdb2e2 + val guineaPig = Apply(TypeApply(Select(Select(gen.mkRuntimeUniverseRef, nme.TypeTag), nme.apply), List(TypeTree(tpe))), List(Literal(Constant(null)), Literal(Constant(null)))) + val isGoodTpe = typer.silent(_.typed(guineaPig)) match { case analyzer.SilentResultValue(_) => true; case _ => false } + TypeTree(if (isGoodTpe) tpe else AnyTpe) + } + object ReifiedTree { def apply(universe: Tree, mirror: Tree, symtab: SymbolTable, rtree: Tree, tpe: Type, rtpe: Tree, concrete: Boolean): Tree = { val tagFactory = if (concrete) nme.TypeTag else nme.WeakTypeTag - val tagCtor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), tagFactory), nme.apply), List(TypeTree(tpe))) - val exprCtor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), nme.Expr), nme.apply), List(TypeTree(tpe))) + val tagCtor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), tagFactory), nme.apply), List(mkTarg(tpe))) + val exprCtor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), nme.Expr), nme.apply), List(mkTarg(tpe))) val tagArgs = List(Ident(nme.MIRROR_SHORT), mkCreator(tpnme.REIFY_TYPECREATOR_PREFIX, symtab, rtpe)) val unwrapped = Apply(Apply(exprCtor, List(Ident(nme.MIRROR_SHORT), mkCreator(tpnme.REIFY_TREECREATOR_PREFIX, symtab, rtree))), List(Apply(tagCtor, tagArgs))) mkWrapper(universe, mirror, unwrapped) @@ -123,7 +131,7 @@ trait Extractors { object ReifiedType { def apply(universe: Tree, mirror: Tree, symtab: SymbolTable, tpe: Type, rtpe: Tree, concrete: Boolean) = { val tagFactory = if (concrete) nme.TypeTag else nme.WeakTypeTag - val ctor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), tagFactory), nme.apply), List(TypeTree(tpe))) + val ctor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), tagFactory), nme.apply), List(mkTarg(tpe))) val args = List(Ident(nme.MIRROR_SHORT), mkCreator(tpnme.REIFY_TYPECREATOR_PREFIX, symtab, rtpe)) val unwrapped = Apply(ctor, args) mkWrapper(universe, mirror, unwrapped) diff --git a/test/files/run/macro-reify-type.check b/test/files/run/macro-reify-type.check new file mode 100644 index 0000000000..ea5e70e10d --- /dev/null +++ b/test/files/run/macro-reify-type.check @@ -0,0 +1 @@ +[B, That](f: Int => B)(implicit bf: scala.collection.generic.CanBuildFrom[List[Int],B,That])That \ No newline at end of file diff --git a/test/files/run/macro-reify-type.flags b/test/files/run/macro-reify-type.flags new file mode 100644 index 0000000000..cd66464f2f --- /dev/null +++ b/test/files/run/macro-reify-type.flags @@ -0,0 +1 @@ +-language:experimental.macros \ No newline at end of file diff --git a/test/files/run/macro-reify-type/Macros_1.scala b/test/files/run/macro-reify-type/Macros_1.scala new file mode 100644 index 0000000000..aeec9fc97c --- /dev/null +++ b/test/files/run/macro-reify-type/Macros_1.scala @@ -0,0 +1,27 @@ +import scala.reflect.macros.Context +import scala.reflect.runtime.{universe => ru} + +object StaticReflect { + def method[A](name: String): ru.Type = macro methodImpl[A] + + def methodImpl[A: c.WeakTypeTag](c: Context)(name: c.Expr[String]): c.Expr[ru.Type] = { + import c.universe._ + + val nameName: TermName = name.tree match { + case Literal(Constant(str: String)) => newTermName(str) + case _ => c.error(c.enclosingPosition, s"Method name not constant.") ; return reify(ru.NoType) + } + val clazz = weakTypeOf[A] + + clazz member nameName match { + case NoSymbol => c.error(c.enclosingPosition, s"No member called $nameName in $clazz.") ; reify(ru.NoType) + case member => + val mtpe = member typeSignatureIn clazz + val mtag = c.reifyType(c.runtimeUniverse, Select(c.runtimeUniverse, newTermName("rootMirror")), mtpe) + val mtree = Select(mtag, newTermName("tpe")) + + c.Expr[ru.Type](mtree) + } + } + +} diff --git a/test/files/run/macro-reify-type/Test_2.scala b/test/files/run/macro-reify-type/Test_2.scala new file mode 100644 index 0000000000..9beaf98681 --- /dev/null +++ b/test/files/run/macro-reify-type/Test_2.scala @@ -0,0 +1,21 @@ +import StaticReflect._ + +object Test extends App { + //println(method[List[Int]]("distinct")) + println(method[List[Int]]("map")) + //val $u: scala.reflect.runtime.universe.type = scala.reflect.runtime.universe; + //val $m: $u.Mirror = scala.reflect.runtime.universe.rootMirror; + //import $u._, $m._, Flag._ + //val tpe = { + // val symdef$B2 = build.newNestedSymbol(build.selectTerm(staticClass("scala.collection.TraversableLike"), "map"), newTypeName("B"), NoPosition, DEFERRED | PARAM, false); + // val symdef$That2 = build.newNestedSymbol(build.selectTerm(staticClass("scala.collection.TraversableLike"), "map"), newTypeName("That"), NoPosition, DEFERRED | PARAM, false); + // val symdef$f2 = build.newNestedSymbol(build.selectTerm(staticClass("scala.collection.TraversableLike"), "map"), newTermName("f"), NoPosition, PARAM, false); + // val symdef$bf2 = build.newNestedSymbol(build.selectTerm(staticClass("scala.collection.TraversableLike"), "map"), newTermName("bf"), NoPosition, IMPLICIT | PARAM, false); + // build.setTypeSignature(symdef$B2, TypeBounds(staticClass("scala.Nothing").asType.toTypeConstructor, staticClass("scala.Any").asType.toTypeConstructor)); + // build.setTypeSignature(symdef$That2, TypeBounds(staticClass("scala.Nothing").asType.toTypeConstructor, staticClass("scala.Any").asType.toTypeConstructor)); + // build.setTypeSignature(symdef$f2, TypeRef(ThisType(staticPackage("scala").asModule.moduleClass), staticClass("scala.Function1"), List(staticClass("scala.Int").asType.toTypeConstructor, TypeRef(NoPrefix, symdef$B2, List())))); + // build.setTypeSignature(symdef$bf2, TypeRef(ThisType(staticPackage("scala.collection.generic").asModule.moduleClass), staticClass("scala.collection.generic.CanBuildFrom"), List(TypeRef(ThisType(staticPackage("scala.collection.immutable").asModule.moduleClass), staticClass("scala.collection.immutable.List"), List(staticClass("scala.Int").asType.toTypeConstructor)), TypeRef(NoPrefix, symdef$B2, List()), TypeRef(NoPrefix, symdef$That2, List())))); + // PolyType(List(symdef$B2, symdef$That2), MethodType(List(symdef$f2), MethodType(List(symdef$bf2), TypeRef(NoPrefix, symdef$That2, List())))) + //} + //println(tpe) +} \ No newline at end of file -- cgit v1.2.3 From b5b614444cefe84861b06a09fbaf10d100556556 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 27 Sep 2012 16:12:50 -0700 Subject: Implementations of isValueType and isNonValueType. Restrictions regarding how non-value types can be used have generally not been enforced explicitly, depending instead on the fact that the compiler wouldn't attempt to use them in strange ways like offering a method type as a type argument. Since users can now create most types from scratch, it has become important to enforce the restrictions in a more direct fashion. This was a lot harder than it probably should have been because there are so many types which go unmentioned by the specification. Hopefully a useful exercise in any case. --- .../scala/reflect/reify/utils/Extractors.scala | 13 ++- src/reflect/scala/reflect/internal/Types.scala | 116 ++++++++++++++++++++- test/files/run/fail-non-value-types.check | 2 + test/files/run/fail-non-value-types.scala | 30 ++++++ test/files/run/macro-reify-type/Macros_1.scala | 2 +- 5 files changed, 150 insertions(+), 13 deletions(-) create mode 100644 test/files/run/fail-non-value-types.check create mode 100644 test/files/run/fail-non-value-types.scala (limited to 'src') diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala index 523520749b..b60d15c1d4 100644 --- a/src/compiler/scala/reflect/reify/utils/Extractors.scala +++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala @@ -92,13 +92,12 @@ trait Extractors { Block(List(universeAlias, mirrorAlias), wrappee) } - private def mkTarg(tpe: Type): Tree = { - // if we're reifying a MethodType, we can't use it as a type argument for TypeTag ctor - // http://groups.google.com/group/scala-internals/browse_thread/thread/2d7bb85bfcdb2e2 - val guineaPig = Apply(TypeApply(Select(Select(gen.mkRuntimeUniverseRef, nme.TypeTag), nme.apply), List(TypeTree(tpe))), List(Literal(Constant(null)), Literal(Constant(null)))) - val isGoodTpe = typer.silent(_.typed(guineaPig)) match { case analyzer.SilentResultValue(_) => true; case _ => false } - TypeTree(if (isGoodTpe) tpe else AnyTpe) - } + // if we're reifying a MethodType, we can't use it as a type argument for TypeTag ctor + // http://groups.google.com/group/scala-internals/browse_thread/thread/2d7bb85bfcdb2e2 + private def mkTarg(tpe: Type): Tree = ( + if ((tpe eq null) || !isUseableAsTypeArg(tpe)) TypeTree(AnyTpe) + else TypeTree(tpe) + ) object ReifiedTree { def apply(universe: Tree, mirror: Tree, symtab: SymbolTable, rtree: Tree, tpe: Type, rtpe: Tree, concrete: Boolean): Tree = { diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 6b274467fc..0e8665ee84 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -66,9 +66,9 @@ import util.ThreeValues._ // a type variable // Replace occurrences of type parameters with type vars, where // inst is the instantiation and constr is a list of bounds. - case DeBruijnIndex(level, index) + case DeBruijnIndex(level, index, args) // for dependent method types: a type referring to a method parameter. - case ErasedValueType(clazz, underlying) + case ErasedValueType(tref) // only used during erasure of derived value classes. */ @@ -3623,9 +3623,20 @@ trait Types extends api.Types { self: SymbolTable => */ /** A creator for type applications */ - def appliedType(tycon: Type, args: List[Type]): Type = - if (args.isEmpty) tycon //@M! `if (args.isEmpty) tycon' is crucial (otherwise we create new types in phases after typer and then they don't get adapted (??)) - else tycon match { + def appliedType(tycon: Type, args: List[Type]): Type = { + if (args.isEmpty) + return tycon //@M! `if (args.isEmpty) tycon' is crucial (otherwise we create new types in phases after typer and then they don't get adapted (??)) + + /** Disabled - causes cycles in tcpoly tests. */ + if (false && isDefinitionsInitialized) { + assert(isUseableAsTypeArgs(args), { + val tapp_s = s"""$tycon[${args mkString ", "}]""" + val arg_s = args filterNot isUseableAsTypeArg map (t => t + "/" + t.getClass) mkString ", " + s"$tapp_s includes illegal type argument $arg_s" + }) + } + + tycon match { case TypeRef(pre, sym @ (NothingClass|AnyClass), _) => copyTypeRef(tycon, pre, sym, Nil) //@M drop type args to Any/Nothing case TypeRef(pre, sym, _) => copyTypeRef(tycon, pre, sym, args) case PolyType(tparams, restpe) => restpe.instantiateTypeParams(tparams, args) @@ -3639,6 +3650,7 @@ trait Types extends api.Types { self: SymbolTable => case WildcardType => tycon // needed for neg/t0226 case _ => abort(debugString(tycon)) } + } /** Very convenient. */ def appliedType(tyconSym: Symbol, args: Type*): Type = @@ -5732,6 +5744,100 @@ trait Types extends api.Types { self: SymbolTable => case _ => false } + /** This is defined and named as it is because the goal is to exclude source + * level types which are not value types (e.g. MethodType) without excluding + * necessary internal types such as WildcardType. There are also non-value + * types which can be used as type arguments (e.g. type constructors.) + */ + def isUseableAsTypeArg(tp: Type) = ( + isInternalTypeUsedAsTypeArg(tp) // the subset of internal types which can be type args + || isHKTypeRef(tp) // not a value type, but ok as a type arg + || isValueElseNonValue(tp) // otherwise only value types + ) + + private def isHKTypeRef(tp: Type) = tp match { + case TypeRef(_, sym, Nil) => tp.isHigherKinded + case _ => false + } + @tailrec final def isUseableAsTypeArgs(tps: List[Type]): Boolean = tps match { + case Nil => true + case x :: xs => isUseableAsTypeArg(x) && isUseableAsTypeArgs(xs) + } + + /** The "third way", types which are neither value types nor + * non-value types as defined in the SLS, further divided into + * types which are used internally in type applications and + * types which are not. + */ + private def isInternalTypeNotUsedAsTypeArg(tp: Type): Boolean = tp match { + case AntiPolyType(pre, targs) => true + case ClassInfoType(parents, defs, clazz) => true + case DeBruijnIndex(level, index, args) => true + case ErasedValueType(tref) => true + case NoPrefix => true + case NoType => true + case SuperType(thistpe, supertpe) => true + case TypeBounds(lo, hi) => true + case _ => false + } + private def isInternalTypeUsedAsTypeArg(tp: Type): Boolean = tp match { + case WildcardType => true + case BoundedWildcardType(_) => true + case ErrorType => true + case _: TypeVar => true + case _ => false + } + private def isAlwaysValueType(tp: Type) = tp match { + case RefinedType(_, _) => true + case ExistentialType(_, _) => true + case ConstantType(_) => true + case _ => false + } + private def isAlwaysNonValueType(tp: Type) = tp match { + case OverloadedType(_, _) => true + case NullaryMethodType(_) => true + case MethodType(_, _) => true + case PolyType(_, MethodType(_, _)) => true + case _ => false + } + /** Should be called only with types for which a clear true/false answer + * can be given: true == value type, false == non-value type. Otherwise, + * an exception is thrown. + */ + private def isValueElseNonValue(tp: Type): Boolean = tp match { + case tp if isAlwaysValueType(tp) => true + case tp if isAlwaysNonValueType(tp) => false + case AnnotatedType(_, underlying, _) => isValueElseNonValue(underlying) + case SingleType(_, sym) => sym.isValue // excludes packages and statics + case TypeRef(_, _, _) if tp.isHigherKinded => false // excludes type constructors + case ThisType(sym) => !sym.isPackageClass // excludes packages + case TypeRef(_, sym, _) => !sym.isPackageClass // excludes packages + case PolyType(_, _) => true // poly-methods excluded earlier + case tp => sys.error("isValueElseNonValue called with third-way type " + tp) + } + + /** SLS 3.2, Value Types + * Is the given type definitely a value type? A true result means + * it verifiably is, but a false result does not mean it is not, + * only that it cannot be assured. To avoid false positives, this + * defaults to false, but since Type is not sealed, one should take + * a false answer with a grain of salt. This method may be primarily + * useful as documentation; it is likely that !isNonValueType(tp) + * will serve better than isValueType(tp). + */ + def isValueType(tp: Type) = isValueElseNonValue(tp) + + /** SLS 3.3, Non-Value Types + * Is the given type definitely a non-value type, as defined in SLS 3.3? + * The specification-enumerated non-value types are method types, polymorphic + * method types, and type constructors. Supplements to the specified set of + * non-value types include: types which wrap non-value symbols (packages + * abd statics), overloaded types. Varargs and by-name types T* and (=>T) are + * not designated non-value types because there is code which depends on using + * them as type arguments, but their precise status is unclear. + */ + def isNonValueType(tp: Type) = !isValueElseNonValue(tp) + def isNonRefinementClassType(tpe: Type) = tpe match { case SingleType(_, sym) => sym.isModuleClass case TypeRef(_, sym, _) => sym.isClass && !sym.isRefinementClass diff --git a/test/files/run/fail-non-value-types.check b/test/files/run/fail-non-value-types.check new file mode 100644 index 0000000000..1c2d7dcf1b --- /dev/null +++ b/test/files/run/fail-non-value-types.check @@ -0,0 +1,2 @@ +[B, That](f: A => B)(implicit cbf: ImaginaryCanBuildFrom[CompletelyIndependentList.this.Repr,B,That])That +()CompletelyIndependentList[A] diff --git a/test/files/run/fail-non-value-types.scala b/test/files/run/fail-non-value-types.scala new file mode 100644 index 0000000000..d9aa5c01ca --- /dev/null +++ b/test/files/run/fail-non-value-types.scala @@ -0,0 +1,30 @@ +import scala.reflect.runtime.universe._ + +class ImaginaryCanBuildFrom[-From, -Elem, +To] +class CompletelyIndependentList[+A] { + type Repr <: CompletelyIndependentList[A] + def map[B, That](f: A => B)(implicit cbf: ImaginaryCanBuildFrom[Repr, B, That]): That = ??? + def distinct(): CompletelyIndependentList[A] = ??? +} + +object Test { + var failed = false + def expectFailure[T](body: => T): Boolean = { + try { val res = body ; failed = true ; println(res + " failed to fail.") ; false } + catch { case _: AssertionError => true } + } + + /** Attempt to use a method type as a type argument - expect failure. */ + def tcon[T: TypeTag](args: Type*) = appliedType(typeOf[T].typeConstructor, args.toList) + + val map = typeOf[CompletelyIndependentList[Int]].member("map": TermName).typeSignature + val distinct = typeOf[CompletelyIndependentList[Int]].member("distinct": TermName).typeSignature + + def main(args: Array[String]): Unit = { + expectFailure(println(tcon[CompletelyIndependentList[Int]](map))) + expectFailure(tcon[CompletelyIndependentList[Int]](distinct)) + println(map) + println(distinct) + if (failed) sys.exit(1) + } +} diff --git a/test/files/run/macro-reify-type/Macros_1.scala b/test/files/run/macro-reify-type/Macros_1.scala index aeec9fc97c..06de05735d 100644 --- a/test/files/run/macro-reify-type/Macros_1.scala +++ b/test/files/run/macro-reify-type/Macros_1.scala @@ -17,7 +17,7 @@ object StaticReflect { case NoSymbol => c.error(c.enclosingPosition, s"No member called $nameName in $clazz.") ; reify(ru.NoType) case member => val mtpe = member typeSignatureIn clazz - val mtag = c.reifyType(c.runtimeUniverse, Select(c.runtimeUniverse, newTermName("rootMirror")), mtpe) + val mtag = c.reifyType(treeBuild.mkRuntimeUniverseRef, Select(treeBuild.mkRuntimeUniverseRef, newTermName("rootMirror")), mtpe) val mtree = Select(mtag, newTermName("tpe")) c.Expr[ru.Type](mtree) -- cgit v1.2.3 From c395c926216b4356c82c606b76784a184a7f1d9b Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 28 Sep 2012 14:20:27 +0200 Subject: fully initializes symbols on `typeSignature` only affects runtime reflection, because Symbol.typeSignature is only defined in the reflection API. the rest of the compiler uses Symbol.info instead. --- src/reflect/scala/reflect/internal/Symbols.scala | 4 ++-- test/files/run/fail-non-value-types.check | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 21506a498d..d387ad764d 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -91,8 +91,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => def module = sourceModule def thisPrefix: Type = thisType def selfType: Type = typeOfThis - def typeSignature: Type = info - def typeSignatureIn(site: Type): Type = site memberInfo this + def typeSignature: Type = { fullyInitializeSymbol(this); info } + def typeSignatureIn(site: Type): Type = { fullyInitializeSymbol(this); site memberInfo this } def toType: Type = tpe def toTypeIn(site: Type): Type = site.memberType(this) diff --git a/test/files/run/fail-non-value-types.check b/test/files/run/fail-non-value-types.check index 4e80a11420..714dce2c50 100644 --- a/test/files/run/fail-non-value-types.check +++ b/test/files/run/fail-non-value-types.check @@ -1,3 +1,3 @@ -[B <: , That <: ](f: )(implicit cbf: )That +[B, That](f: A => B)(implicit cbf: ImaginaryCanBuildFrom[CompletelyIndependentList.this.Repr,B,That])That [B, That](f: Int => B)(implicit cbf: ImaginaryCanBuildFrom[CompletelyIndependentList[Int]#Repr,B,That])That ()CompletelyIndependentList[A] -- cgit v1.2.3