Skip to content

Commit 724b0dc

Browse files
committed
Implicits to encourage more Name-dropping.
This creates implicits in cakes across the land from: String => TermName String => TypeName And also from: Name => NameOps[Name] // lower priority TermName => NameOps[TermName] TypeName => NameOps[TypeName] What this is all about, using "drop" as a motivating example, is that these should all work: "abc" drop 1 // "bc": String ("abc": TermName) drop 1 // "bc": TermName ("abc": TypeName) drop 1 // "bc": TypeName (("abc": TypeName): Name) drop 1 // "bc": Name But this should not: ("bc": Name) // ambiguity error This requires drop not being directly on Name; peer implicits from String => TermName and String => TypeName; implicit classes to install drop on TermName and TypeName; and a lower priority implicit class to allow ops on Names. Review by @xeno.by .
1 parent c632aac commit 724b0dc

File tree

12 files changed

+73
-21
lines changed

12 files changed

+73
-21
lines changed

src/compiler/scala/reflect/reify/utils/NodePrinters.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ trait NodePrinters {
4242
val buf = new collection.mutable.ListBuffer[String]
4343

4444
val annotations = m.group(3)
45-
if (buf.nonEmpty || annotations.nonEmpty)
45+
if (buf.nonEmpty || annotations != "")
4646
buf.append("List(" + annotations + ")")
4747

4848
val privateWithin = "" + m.group(2)

src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ trait ScratchPadMaker { self: Global =>
9292
case PackageDef(_, _) =>
9393
super.traverse(tree)
9494
case ModuleDef(_, name, Template(_, _, body)) =>
95-
if (objectName.length == 0 /* objectName.isEmpty does not compile on Java 5 due to ambiguous implicit conversions: augmentString, stringToTermName */)
95+
if (objectName.length == 0)
9696
objectName = tree.symbol.fullName
9797
body foreach traverseStat
9898
applyPendingPatches(skipped)

src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ abstract class TypeParser {
3535

3636
protected var busy: Boolean = false // lock to detect recursive reads
3737

38-
private implicit def stringToTermName(s: String): TermName = newTermName(s)
39-
4038
private object unpickler extends UnPickler {
4139
val global: TypeParser.this.global.type = TypeParser.this.global
4240
}
@@ -260,8 +258,8 @@ abstract class TypeParser {
260258
|| ntype.IsInterface /* TODO why shouldn't nested ifaces be type-parsed too? */ )
261259
{
262260
val loader = new loaders.MsilFileLoader(new MsilFile(ntype))
263-
val nclazz = statics.newClass(ntype.Name.toTypeName)
264-
val nmodule = statics.newModule(ntype.Name)
261+
val nclazz = statics.newClass(ntype.Name)
262+
val nmodule = statics.newModule(ntype.Name)
265263
nclazz.setInfo(loader)
266264
nmodule.setInfo(loader)
267265
staticDefs.enter(nclazz)
@@ -311,7 +309,7 @@ abstract class TypeParser {
311309
assert(prop.PropertyType == getter.ReturnType);
312310
val gparams: Array[ParameterInfo] = getter.GetParameters();
313311
gparamsLength = gparams.length;
314-
val name: Name = if (gparamsLength == 0) prop.Name else nme.apply;
312+
val name: TermName = if (gparamsLength == 0) prop.Name else nme.apply;
315313
val flags = translateAttributes(getter);
316314
val owner: Symbol = if (getter.IsStatic) statics else clazz;
317315
val methodSym = owner.newMethod(name, NoPosition, flags)
@@ -333,7 +331,7 @@ abstract class TypeParser {
333331
if(getter != null)
334332
assert(sparams.length == gparamsLength + 1, "" + getter + "; " + setter);
335333

336-
val name: Name = if (gparamsLength == 0) nme.getterToSetter(prop.Name)
334+
val name: TermName = if (gparamsLength == 0) nme.getterToSetter(prop.Name)
337335
else nme.update;
338336
val flags = translateAttributes(setter);
339337
val mtype = methodType(setter, definitions.UnitClass.tpe);
@@ -494,13 +492,13 @@ abstract class TypeParser {
494492
else clrTypes.methods(methodSym) = method.asInstanceOf[MethodInfo];
495493
}
496494

497-
private def createMethod(name: Name, flags: Long, args: Array[MSILType], retType: MSILType, method: MethodInfo, statik: Boolean): Symbol = {
495+
private def createMethod(name: TermName, flags: Long, args: Array[MSILType], retType: MSILType, method: MethodInfo, statik: Boolean): Symbol = {
498496
val mtype = methodType(args, getCLSType(retType))
499497
assert(mtype != null)
500498
createMethod(name, flags, mtype, method, statik)
501499
}
502500

503-
private def createMethod(name: Name, flags: Long, mtype: Symbol => Type, method: MethodInfo, statik: Boolean): Symbol = {
501+
private def createMethod(name: TermName, flags: Long, mtype: Symbol => Type, method: MethodInfo, statik: Boolean): Symbol = {
504502
val methodSym: Symbol = (if (statik) statics else clazz).newMethod(name)
505503
methodSym.setFlag(flags).setInfo(mtype(methodSym))
506504
(if (statik) staticDefs else instanceDefs).enter(methodSym)
@@ -541,7 +539,7 @@ abstract class TypeParser {
541539
s = createMethod(nme.MINUS, flags, args, typ, clrTypes.DELEGATE_REMOVE, false);
542540
}
543541

544-
private def getName(method: MethodBase): Name = {
542+
private def getName(method: MethodBase): TermName = {
545543

546544
def operatorOverload(name : String, paramsArity : Int) : Option[Name] = paramsArity match {
547545
case 1 => name match {
@@ -653,7 +651,7 @@ abstract class TypeParser {
653651

654652
private def getClassType(typ: MSILType): Type = {
655653
assert(typ != null);
656-
val res = rootMirror.getClassByName(typ.FullName.replace('+', '.')).tpe;
654+
val res = rootMirror.getClassByName(typ.FullName.replace('+', '.') : TypeName).tpe;
657655
//if (res.isError())
658656
// global.reporter.error("unknown class reference " + type.FullName);
659657
res

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4283,7 +4283,7 @@ trait Typers extends Modes with Adaptations with Tags {
42834283
}
42844284

42854285
def convertToAssignment(fun: Tree, qual: Tree, name: Name, args: List[Tree]): Tree = {
4286-
val prefix = name stripSuffix nme.EQL
4286+
val prefix = name.toTermName stripSuffix nme.EQL
42874287
def mkAssign(vble: Tree): Tree =
42884288
Assign(
42894289
vble,

src/library/scala/reflect/base/Names.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ package base
1111
* `name1 == name2` implies `name1 eq name2`.
1212
*/
1313
trait Names {
14+
/** Intentionally no implicit from String => Name. */
15+
implicit def stringToTermName(s: String): TermName = newTermName(s)
16+
implicit def stringToTypeName(s: String): TypeName = newTypeName(s)
1417

1518
/** The abstract type of names */
1619
type Name >: Null <: NameBase

src/reflect/scala/reflect/internal/Names.scala

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,18 @@ import scala.io.Codec
1010
import java.security.MessageDigest
1111
import language.implicitConversions
1212

13+
trait LowPriorityNames {
14+
self: Names =>
15+
16+
implicit def nameToNameOps(name: Name): NameOps[Name] = new NameOps[Name](name)
17+
}
18+
1319
/** The class Names ...
1420
*
1521
* @author Martin Odersky
1622
* @version 1.0, 05/02/2005
1723
*/
18-
trait Names extends api.Names {
24+
trait Names extends api.Names with LowPriorityNames {
1925
implicit def promoteTermNamesAsNecessary(name: Name): TermName = name.toTermName
2026

2127
// Operations -------------------------------------------------------------
@@ -356,11 +362,6 @@ trait Names extends api.Names {
356362
final def endsWith(char: Char): Boolean = len > 0 && endChar == char
357363
final def endsWith(name: String): Boolean = endsWith(newTermName(name))
358364

359-
def dropRight(n: Int): ThisNameType = subName(0, len - n)
360-
def drop(n: Int): ThisNameType = subName(n, len)
361-
def stripSuffix(suffix: Name): ThisNameType =
362-
if (this endsWith suffix) dropRight(suffix.length) else thisName
363-
364365
def indexOf(ch: Char) = {
365366
val idx = pos(ch)
366367
if (idx == length) -1 else idx
@@ -429,6 +430,16 @@ trait Names extends api.Names {
429430
def debugString = { val s = decode ; if (isTypeName) s + "!" else s }
430431
}
431432

433+
implicit def TermNameOps(name: TermName): NameOps[TermName] = new NameOps(name)
434+
implicit def TypeNameOps(name: TypeName): NameOps[TypeName] = new NameOps(name)
435+
436+
final class NameOps[T <: Name](name: T) {
437+
def stripSuffix(suffix: Name): T = if (name endsWith suffix) dropRight(suffix.length) else name
438+
def dropRight(n: Int): T = name.subName(0, name.length - n).asInstanceOf[T]
439+
def drop(n: Int): T = name.subName(n, name.length).asInstanceOf[T]
440+
def nonEmpty: Boolean = name.length > 0
441+
}
442+
432443
implicit val NameTag = ClassTag[Name](classOf[Name])
433444

434445
/** A name that contains no operator chars nor dollar signs.

src/reflect/scala/reflect/internal/StdNames.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ trait StdNames {
8484

8585
abstract class CommonNames extends NamesApi {
8686
type NameType >: Null <: Name
87+
// Masking some implicits so as to allow our targeted => NameType.
88+
protected val stringToTermName = null
89+
protected val stringToTypeName = null
8790
protected implicit def createNameType(name: String): NameType
8891

8992
def flattenedName(segments: Name*): NameType =
@@ -963,7 +966,7 @@ trait StdNames {
963966
case -1 => if (name == "") scala.Nil else scala.List(mkName(name, assumeTerm))
964967
// otherwise, we can tell based on whether '#' or '.' is the following char.
965968
case idx =>
966-
val (simple, div, rest) = (name take idx, name charAt idx, newTermName(name) drop (idx + 1))
969+
val (simple, div, rest) = (name take idx, name charAt idx, name drop idx + 1)
967970
mkName(simple, div == '.') :: segments(rest, assumeTerm)
968971
}
969972
}
@@ -1038,6 +1041,8 @@ trait StdNames {
10381041
}
10391042

10401043
abstract class SymbolNames {
1044+
protected val stringToTermName = null
1045+
protected val stringToTypeName = null
10411046
protected implicit def createNameType(s: String): TypeName = newTypeNameCached(s)
10421047

10431048
val BeanProperty : TypeName

src/reflect/scala/reflect/runtime/JavaMirrors.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,7 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym
658658
val ownerModule: ModuleSymbol =
659659
if (split > 0) packageNameToScala(fullname take split) else this.RootPackage
660660
val owner = ownerModule.moduleClass
661-
val name = newTermName(fullname drop (split + 1))
661+
val name = (fullname: TermName) drop split + 1
662662
val opkg = owner.info decl name
663663
if (opkg.isPackage)
664664
opkg.asModuleSymbol
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
reflection-names-neg.scala:5: error: type mismatch;
2+
found : String("abc")
3+
required: reflect.runtime.universe.Name
4+
Note that implicit conversions are not applicable because they are ambiguous:
5+
both method stringToTermName in trait Names of type (s: String)reflect.runtime.universe.TermName
6+
and method stringToTypeName in trait Names of type (s: String)reflect.runtime.universe.TypeName
7+
are possible conversion functions from String("abc") to reflect.runtime.universe.Name
8+
val x2 = ("abc": Name) drop 1 // error
9+
^
10+
one error found
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import scala.reflect.runtime.universe._
2+
3+
object Test {
4+
val x1 = "abc" drop 1 // "bc": String
5+
val x2 = ("abc": Name) drop 1 // error
6+
}

0 commit comments

Comments
 (0)