diff --git a/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala b/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala index 2ee1b6011ec7..80a0cf0f694e 100644 --- a/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala +++ b/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala @@ -68,7 +68,7 @@ object CollectEntryPoints{ def fail(msg: String, pos: Position = sym.pos) = { ctx.warning( sym.name + s" has a main method with parameter type Array[String], but ${toDenot(sym).fullName} will not be a runnable program.\n Reason: $msg", - sourcePos(sym.pos) + pos // TODO: make this next claim true, if possible // by generating valid main methods as static in module classes // not sure what the jvm allows here diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 51fa15706c08..8345d45f6832 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -15,6 +15,7 @@ import scala.reflect.internal.util.WeakHashSet import scala.reflect.io.{AbstractFile, Directory, PlainDirectory} import scala.tools.asm.{AnnotationVisitor, ClassVisitor, FieldVisitor, MethodVisitor} import scala.tools.nsc.backend.jvm.{BCodeHelpers, BackendInterface} +import dotty.tools.dotc.util.SourcePosition import dotty.tools.dotc.core._ import Periods._ import SymDenotations._ @@ -481,13 +482,13 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma - implicit def positionHelper(a: Position): PositionHelper = new PositionHelper { + implicit class positionHelper(a: Position) extends PositionHelper { def isDefined: Boolean = a.exists - def line: Int = sourcePos(a).line + 1 + def line: Int = SourcePosition(a).line + 1 def finalPosition: Position = a } - implicit def constantHelper(a: Constant): ConstantHelper = new ConstantHelper { + implicit class constantHelper(a: Constant) extends ConstantHelper { def booleanValue: Boolean = a.booleanValue def longValue: Long = a.longValue def byteValue: Byte = a.byteValue @@ -503,8 +504,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def charValue: Char = a.charValue } - - implicit def treeHelper(a: Tree): TreeHelper = new TreeHelper { + implicit class treeHelper(a: Tree) extends TreeHelper { def symbol: Symbol = a.symbol def pos: Position = a.pos @@ -517,7 +517,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma } - implicit def annotHelper(a: Annotation): AnnotationHelper = new AnnotationHelper { + implicit class annotHelper(a: Annotation) extends AnnotationHelper { def atp: Type = a.tree.tpe def assocs: List[(Name, Tree)] = assocsFromApply(a.tree) @@ -538,7 +538,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma } - implicit def nameHelper(n: Name): NameHelper = new NameHelper { + implicit class nameHelper(n: Name) extends NameHelper { def toTypeName: Name = n.toTypeName def isTypeName: Boolean = n.isTypeName def toTermName: Name = n.toTermName @@ -551,7 +551,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma } - implicit def symHelper(sym: Symbol): SymbolHelper = new SymbolHelper { + implicit class symHelper(sym: Symbol) extends SymbolHelper { // names def fullName(sep: Char): String = sym.showFullName def fullName: String = sym.showFullName @@ -778,7 +778,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma } - implicit def typeHelper(tp: Type): TypeHelper = new TypeHelper { + implicit class typeHelper(tp: Type) extends TypeHelper { def member(string: Name): Symbol = tp.member(string.toTermName).symbol def isFinalType: Boolean = tp.typeSymbol is Flags.Final //in scalac checks for type parameters. Why? Aren't they gone by backend? diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index b5be894402fa..53e8b4560676 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -118,7 +118,7 @@ object desugar { vparamss = (setterParam :: Nil) :: Nil, tpt = TypeTree(defn.UnitType), rhs = setterRhs - ).withMods((mods | Accessor) &~ CaseAccessor) // rhs gets filled in later, when field is generated and getter has parameters + ).withMods((mods | Accessor) &~ (CaseAccessor | Implicit)) // rhs gets filled in later, when field is generated and getter has parameters Thicket(vdef, setter) } else vdef diff --git a/compiler/src/dotty/tools/dotc/core/Decorators.scala b/compiler/src/dotty/tools/dotc/core/Decorators.scala index a105741f5b6d..1d85ef9509b0 100644 --- a/compiler/src/dotty/tools/dotc/core/Decorators.scala +++ b/compiler/src/dotty/tools/dotc/core/Decorators.scala @@ -4,10 +4,8 @@ package core import annotation.tailrec import Symbols._ import Contexts._, Names._, Phases._, printing.Texts._, printing.Printer, printing.Showable -import util.Positions.Position, util.SourcePosition import collection.mutable.ListBuffer import dotty.tools.dotc.transform.TreeTransforms._ -import ast.tpd._ import scala.language.implicitConversions import printing.Formatting._ @@ -149,16 +147,6 @@ object Decorators { } } - implicit def sourcePos(pos: Position)(implicit ctx: Context): SourcePosition = { - def recur(inlinedCalls: List[Tree], pos: Position): SourcePosition = inlinedCalls match { - case inlinedCall :: rest => - sourceFile(inlinedCall).atPos(pos).withOuter(recur(rest, inlinedCall.pos)) - case empty => - ctx.source.atPos(pos) - } - recur(enclosingInlineds, pos) - } - implicit class StringInterpolators(val sc: StringContext) extends AnyVal { /** General purpose string formatting */ diff --git a/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala b/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala index 331fce46ac16..cc376b29ce94 100644 --- a/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala +++ b/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala @@ -49,7 +49,7 @@ class CollectEntryPoints extends MiniPhaseTransform { def fail(msg: String, pos: Position = sym.pos) = { ctx.warning(sym.name + s" has a main method with parameter type Array[String], but ${sym.fullName} will not be a runnable program.\n Reason: $msg", - sourcePos(sym.pos) + pos // TODO: make this next claim true, if possible // by generating valid main methods as static in module classes // not sure what the jvm allows here diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 1ca7eb107c61..741c2ba13005 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -501,10 +501,22 @@ trait Checking { /** Check that a non-implicit parameter making up the first parameter section of an * implicit conversion is not a singleton type. */ - def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = vparamss match { + def checkImplicitConversion(sym: Symbol, vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = vparamss match { case (vparam :: Nil) :: _ if !(vparam.symbol is Implicit) => if (vparam.tpt.tpe.isInstanceOf[SingletonType]) ctx.error(s"implicit conversion may not have a parameter of singleton type", vparam.tpt.pos) + if (!ctx.isAfterTyper && sym.owner.isClass && !sym.is(AccessFlags)) { + val fromTpe = vparam.tpt.tpe + val toTpe = sym.info.finalResultType + val fromClasses = fromTpe.classSymbols + val toClasses = toTpe.classSymbols + def isLocal(cls: ClassSymbol) = + ctx.owner.topLevelClass.associatedFile == cls.associatedFile + if (!fromClasses.exists(isLocal) && !toClasses.forall(isLocal)) + ctx.errorOrMigrationWarning( + em"""implicit conversion must be defined in same compilation unit as its source ${fromClasses.mkString(" or ")} + |or its target ${toClasses.mkString(" and ")}""", sym.pos) + } case _ => } @@ -633,7 +645,7 @@ trait NoChecking extends Checking { override def checkValue(tree: Tree, proto: Type)(implicit ctx: Context): tree.type = tree override def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = () override def checkClassType(tp: Type, pos: Position, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type = tp - override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = () + override def checkImplicitConversion(sym: Symbol, vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = () override def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp override def checkInlineConformant(tree: Tree, what: => String)(implicit ctx: Context) = () override def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = () diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 57e3c1b880a5..4537adb4aba3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1219,7 +1219,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit completeAnnotations(ddef, sym) val tparams1 = tparams mapconserve (typed(_).asInstanceOf[TypeDef]) val vparamss1 = vparamss nestedMapconserve (typed(_).asInstanceOf[ValDef]) - if (sym is Implicit) checkImplicitParamsNotSingletons(vparamss1) + if (sym is Implicit) checkImplicitConversion(sym, vparamss1) var tpt1 = checkSimpleKinded(typedType(tpt)) var rhsCtx = ctx diff --git a/compiler/src/dotty/tools/dotc/util/SourcePosition.scala b/compiler/src/dotty/tools/dotc/util/SourcePosition.scala index be5c469952be..c11001a10a72 100644 --- a/compiler/src/dotty/tools/dotc/util/SourcePosition.scala +++ b/compiler/src/dotty/tools/dotc/util/SourcePosition.scala @@ -51,6 +51,21 @@ extends interfaces.SourcePosition { else s"(no source file, offset = ${pos.point})" } +object SourcePosition { + import core.Contexts.Context + import ast.tpd.{Tree, sourceFile, enclosingInlineds} + + implicit def apply(pos: Position)(implicit ctx: Context): SourcePosition = { + def recur(inlinedCalls: List[Tree], pos: Position): SourcePosition = inlinedCalls match { + case inlinedCall :: rest => + sourceFile(inlinedCall).atPos(pos).withOuter(recur(rest, inlinedCall.pos)) + case empty => + ctx.source.atPos(pos) + } + recur(enclosingInlineds, pos) + } +} + /** A sentinel for a non-existing source position */ @sharable object NoSourcePosition extends SourcePosition(NoSource, NoPosition) { override def toString = "?" diff --git a/compiler/src/dotty/tools/io/Jar.scala b/compiler/src/dotty/tools/io/Jar.scala index 42efc7e0623d..a021ed0a8768 100644 --- a/compiler/src/dotty/tools/io/Jar.scala +++ b/compiler/src/dotty/tools/io/Jar.scala @@ -34,6 +34,8 @@ import scala.language.{postfixOps, implicitConversions} // static Attributes.Name SPECIFICATION_VERSION class Jar(file: File) extends Iterable[JarEntry] { + import Jar.enrichManifest + def this(jfile: JFile) = this(File(jfile)) def this(path: String) = this(File(path)) @@ -133,6 +135,8 @@ object Jar { def apply(manifest: JManifest): WManifest = new WManifest(manifest) implicit def unenrichManifest(x: WManifest): JManifest = x.underlying } + implicit def enrichManifest(m: JManifest): WManifest = WManifest(m) + class WManifest(manifest: JManifest) { for ((k, v) <- initialMainAttrs) this(k) = v diff --git a/compiler/src/dotty/tools/io/package.scala b/compiler/src/dotty/tools/io/package.scala index 1c0e0b5c4471..8f62aaf9e597 100644 --- a/compiler/src/dotty/tools/io/package.scala +++ b/compiler/src/dotty/tools/io/package.scala @@ -30,7 +30,6 @@ package object io { type JManifest = java.util.jar.Manifest type JFile = java.io.File - implicit def enrichManifest(m: JManifest): Jar.WManifest = Jar.WManifest(m) private lazy val daemonThreadPool = DaemonThreadFactory.newPool() def runnable(body: => Unit): Runnable = new Runnable { override def run() = body } diff --git a/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala b/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala index 806e1af46421..16916d3e25f2 100644 --- a/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala +++ b/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala @@ -16,7 +16,7 @@ import core.Flags object ModifiersParsingTest { implicit val ctx: Context = (new ContextBase).initialCtx - implicit def parse(code: String): Tree = { + private implicit def parse(code: String): Tree = { val (_, stats) = new Parser(new SourceFile("", code.toCharArray)).templateStatSeq() stats match { case List(stat) => stat; case stats => Thicket(stats) } } diff --git a/library/src/scala/reflect/Selectable.scala b/library/src/scala/reflect/Selectable.scala index 0dbdbc293d1b..2d1c2e4c3eaa 100644 --- a/library/src/scala/reflect/Selectable.scala +++ b/library/src/scala/reflect/Selectable.scala @@ -66,7 +66,7 @@ class Selectable(val receiver: Any) extends AnyVal with scala.Selectable { } object Selectable { - implicit def reflectiveSelectable(receiver: Any): scala.Selectable = receiver match { + implicit def reflectiveSelectable(receiver: Any): Selectable = receiver match { case receiver: scala.Selectable => receiver case _ => new Selectable(receiver) } diff --git a/tests/neg/function-arity.scala b/tests/neg/function-arity.scala index 5e0cb1058f98..58f03683c3df 100644 --- a/tests/neg/function-arity.scala +++ b/tests/neg/function-arity.scala @@ -23,6 +23,6 @@ object Test { foo((a: Int, b: String) => a + b) // error: none of the overloaded alternatives of method foo match arguments (Int, Int) } object jasonComment { - implicit def i2s(i: Int): String = i.toString + private implicit def i2s(i: Int): String = i.toString ((x: String, y: String) => 42) : (((Int, Int)) => String) // error } diff --git a/tests/neg/implicitDefs.scala b/tests/neg/implicitDefs.scala index 3bfe604341a3..24bc622f85d9 100644 --- a/tests/neg/implicitDefs.scala +++ b/tests/neg/implicitDefs.scala @@ -7,7 +7,7 @@ object implicitDefs { implicit val x = 2 // error: type of implicit definition needs to be given explicitly implicit def y(x: Int) = 3 // error: result type of implicit definition needs to be given explicitly - implicit def z(a: x.type): String = "" // error: implicit conversion may not have a parameter of singleton type + implicit def z(a: x.type): String = "" // error: implicit conversion may not have a parameter of singleton type // error: implicit must be defined in same compilation unit def foo(implicit x: String) = 1 diff --git a/tests/neg/zoo.scala b/tests/neg/zoo.scala index 1674548e842c..fe0af30efa39 100644 --- a/tests/neg/zoo.scala +++ b/tests/neg/zoo.scala @@ -40,5 +40,5 @@ def newLion: Lion = new { } val milka = newCow val leo = newLion -leo.eats(milka) // error: no projector found +leo.eats(milka) // error found: Test.Lion(Test.leo) required: Selectable } diff --git a/tests/new/package-implicit/ActorRef.scala b/tests/pos-scala2/package-implicit/ActorRef.scala similarity index 100% rename from tests/new/package-implicit/ActorRef.scala rename to tests/pos-scala2/package-implicit/ActorRef.scala diff --git a/tests/new/package-implicit/DataFlow.scala b/tests/pos-scala2/package-implicit/DataFlow.scala similarity index 100% rename from tests/new/package-implicit/DataFlow.scala rename to tests/pos-scala2/package-implicit/DataFlow.scala diff --git a/tests/new/package-implicit/package.scala b/tests/pos-scala2/package-implicit/package.scala similarity index 100% rename from tests/new/package-implicit/package.scala rename to tests/pos-scala2/package-implicit/package.scala diff --git a/tests/pos/t2429.scala b/tests/pos-scala2/t2429.scala similarity index 100% rename from tests/pos/t2429.scala rename to tests/pos-scala2/t2429.scala diff --git a/tests/pos/t0438.scala b/tests/pos/t0438.scala index 1615e3da7074..4340eb79a7c7 100644 --- a/tests/pos/t0438.scala +++ b/tests/pos/t0438.scala @@ -1,5 +1,5 @@ class Foo { - implicit def pair2fun2[A, B, C](f: (A, B) => C): ((A, B)) => C = + private implicit def pair2fun2[A, B, C](f: (A, B) => C): ((A, B)) => C = {p: (A, B) => f(p._1, p._2) } def foo(f: ((Int, Int)) => Int) = f diff --git a/tests/pos/typealiases.scala b/tests/pos/typealiases.scala index 93d1dce4dc31..e296bcb29fe1 100644 --- a/tests/pos/typealiases.scala +++ b/tests/pos/typealiases.scala @@ -14,7 +14,7 @@ trait Test[T] { object main extends Test[Int] { val pair1 = (1,1) - implicit def topair(x: Int): Tuple2[Int, Int] = (x,x) + private implicit def topair(x: Int): Tuple2[Int, Int] = (x,x) val pair2: MyPair[Int] = 1 val x: Short = 1 } diff --git a/tests/run/t3346g.check b/tests/run-scala2/t3346g.check similarity index 100% rename from tests/run/t3346g.check rename to tests/run-scala2/t3346g.check diff --git a/tests/run/t3346g.scala b/tests/run-scala2/t3346g.scala similarity index 100% rename from tests/run/t3346g.scala rename to tests/run-scala2/t3346g.scala diff --git a/tests/run/t3346h.check b/tests/run-scala2/t3346h.check similarity index 100% rename from tests/run/t3346h.check rename to tests/run-scala2/t3346h.check diff --git a/tests/run/t3346h.scala b/tests/run-scala2/t3346h.scala similarity index 100% rename from tests/run/t3346h.scala rename to tests/run-scala2/t3346h.scala diff --git a/tests/run/t8280.scala b/tests/run-scala2/t8280.scala similarity index 100% rename from tests/run/t8280.scala rename to tests/run-scala2/t8280.scala diff --git a/tests/run/implicits.check b/tests/run/implicits.check index 010571589cec..4ac46c960066 100644 --- a/tests/run/implicits.check +++ b/tests/run/implicits.check @@ -1,2 +1,2 @@ -OK -[2] +Str(OK) +Str([2]) diff --git a/tests/run/implicits.scala b/tests/run/implicits.scala index 60a361a44d08..b7878d16f6bb 100644 --- a/tests/run/implicits.scala +++ b/tests/run/implicits.scala @@ -1,8 +1,9 @@ import scala.language.implicitConversions +case class Str(str: String) object A { object B { - implicit def int2string(x: Int): String = "["+x.toString+"]" + implicit def int2string(x: Int): Str = Str("["+x.toString+"]") } } @@ -12,8 +13,8 @@ class C(x: String) { } object Inner { - val s: String = x - implicit def Inner2String(x: Inner): String = s + val s: Str = Str(x) + implicit def Inner2Str(x: Inner): Str = s } } @@ -21,9 +22,9 @@ object Test extends dotty.runtime.LegacyApp { import A.B._ val c = new C("OK") val i = new c.Inner - val s: String = i + val s: Str = i Console.println(s) - Console.println(2: String) + Console.println(2: Str) } object TestPriority { diff --git a/tests/run/tcpoly_parseridioms.scala b/tests/run/tcpoly_parseridioms.scala index e86af0caa90a..89a024a90e0c 100644 --- a/tests/run/tcpoly_parseridioms.scala +++ b/tests/run/tcpoly_parseridioms.scala @@ -90,9 +90,9 @@ trait ParserIdioms extends Parsers with Idioms { def pure[a](x: a): Parser[a] = success(x) } - implicit def parserIdiomFun[s, t](fun: s=>t): IdiomaticFunction[Parser, ParserIdiom.type, s, t] = + protected implicit def parserIdiomFun[s, t](fun: s=>t): IdiomaticFunction[Parser, ParserIdiom.type, s, t] = new IdiomaticFunction[Parser, ParserIdiom.type, s, t](ParserIdiom, fun) - implicit def parserIdiomTgt[s](tgt: s): IdiomaticTarget[Parser, ParserIdiom.type, s] = + protected implicit def parserIdiomTgt[s](tgt: s): IdiomaticTarget[Parser, ParserIdiom.type, s] = new IdiomaticTarget[Parser, ParserIdiom.type, s](ParserIdiom, tgt) trait Expr @@ -103,8 +103,8 @@ trait ParserIdioms extends Parsers with Idioms { // TODO: how can parserIdiom(curry2(_)) be omitted? def expr: Parser[Expr] = parserIdiomFun(curry2(Plus)) <| num <> num |> - implicit def curry2[s,t,u](fun: (s, t)=>u)(a: s)(b: t): u = fun(a, b) - implicit def curry3[r,s,t,u](fun: (r,s, t)=>u)(a: r)(b: s)(c: t): u = fun(a, b, c) + protected implicit def curry2[s,t,u](fun: (s, t)=>u)(a: s)(b: t): u = fun(a, b) + protected implicit def curry3[r,s,t,u](fun: (r,s, t)=>u)(a: r)(b: s)(c: t): u = fun(a, b, c) } object Test extends ParserIdioms with App {