From 1c03d45b1649bb8307c09ebfd2bcb3b9efe50dad Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 12 Dec 2016 09:42:29 +0100 Subject: Fix #1784: allow to omit types for local implicit vals --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 12 +++++++++--- tests/pos/implicits.scala | 5 +++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index b8fe46745..e02e90df1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -998,11 +998,17 @@ class Namer { typer: Typer => lhsType // keep constant types that fill in for a non-constant (to be revised when inline has landed). else inherited else { - if (sym is Implicit) { - val resStr = if (mdef.isInstanceOf[DefDef]) "result " else "" - ctx.error(s"${resStr}type of implicit definition needs to be given explicitly", mdef.pos) + def missingType(modifier: String) = { + ctx.error(s"${modifier}type of implicit definition needs to be given explicitly", mdef.pos) sym.resetFlag(Implicit) + } + if (sym is Implicit) + mdef match { + case _: DefDef => missingType("result") + case _: ValDef if sym.owner.isType => missingType("") + case _ => + } lhsType orElse WildcardType } } diff --git a/tests/pos/implicits.scala b/tests/pos/implicits.scala index 1a3e0b4da..feb48771f 100644 --- a/tests/pos/implicits.scala +++ b/tests/pos/implicits.scala @@ -6,4 +6,9 @@ object Test { val x: X = Byte.MinValue + def foo() = { + implicit val x = "abc" + implicitly[String] + } + } -- cgit v1.2.3 From 4c1bf42414b7f7ed99653fe841b032eb11864f2a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 12 Dec 2016 10:42:47 +0100 Subject: Drop explicit types for local implicit vals Drop explicit types for local implicit vals of type Context and Position. Exercises the functionality and shortens the code. --- compiler/sjs/backend/sjs/JSCodeGen.scala | 64 +++++++++++----------- .../dotty/tools/backend/jvm/scalaPrimitives.scala | 2 +- compiler/src/dotty/tools/dotc/ast/Trees.scala | 8 +-- .../src/dotty/tools/dotc/config/PathResolver.scala | 2 +- .../src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- .../src/dotty/tools/dotc/core/TypeComparer.scala | 4 +- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- .../reporting/diagnostic/MessageContainer.scala | 2 +- .../src/dotty/tools/dotc/transform/Erasure.scala | 4 +- .../dotty/tools/dotc/transform/TreeChecker.scala | 2 +- .../src/dotty/tools/dotc/typer/Applications.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Inliner.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 +- 13 files changed, 49 insertions(+), 49 deletions(-) diff --git a/compiler/sjs/backend/sjs/JSCodeGen.scala b/compiler/sjs/backend/sjs/JSCodeGen.scala index 401e01784..69a5651fc 100644 --- a/compiler/sjs/backend/sjs/JSCodeGen.scala +++ b/compiler/sjs/backend/sjs/JSCodeGen.scala @@ -127,7 +127,7 @@ class JSCodeGen()(implicit ctx: Context) { /* Finally, we emit true code for the remaining class defs. */ for (td <- allTypeDefs) { val sym = td.symbol - implicit val pos: Position = sym.pos + implicit val pos = sym.pos /* Do not actually emit code for primitive types nor scala.Array. */ val isPrimitive = @@ -203,7 +203,7 @@ class JSCodeGen()(implicit ctx: Context) { */ private def genScalaClass(td: TypeDef): js.ClassDef = { val sym = td.symbol.asClass - implicit val pos: Position = sym.pos + implicit val pos = sym.pos assert(!sym.is(Trait), "genScalaClass() must be called only for normal classes: "+sym) @@ -336,7 +336,7 @@ class JSCodeGen()(implicit ctx: Context) { */ private def genRawJSClassData(td: TypeDef): js.ClassDef = { val sym = td.symbol.asClass - implicit val pos: Position = sym.pos + implicit val pos = sym.pos val classIdent = encodeClassFullNameIdent(sym) val superClass = @@ -358,7 +358,7 @@ class JSCodeGen()(implicit ctx: Context) { */ private def genInterface(td: TypeDef): js.ClassDef = { val sym = td.symbol.asClass - implicit val pos: Position = sym.pos + implicit val pos = sym.pos val classIdent = encodeClassFullNameIdent(sym) @@ -408,7 +408,7 @@ class JSCodeGen()(implicit ctx: Context) { f <- classSym.info.decls if !f.is(Method) && f.isTerm } yield { - implicit val pos: Position = f.pos + implicit val pos = f.pos val name = /*if (isExposed(f)) js.StringLiteral(jsNameOf(f)) @@ -479,7 +479,7 @@ class JSCodeGen()(implicit ctx: Context) { * Other (normal) methods are emitted with `genMethodBody()`. */ private def genMethodWithCurrentLocalNameScope(dd: DefDef): Option[js.MethodDef] = { - implicit val pos: Position = dd.pos + implicit val pos = dd.pos val sym = dd.symbol val vparamss = dd.vparamss val rhs = dd.rhs @@ -501,7 +501,7 @@ class JSCodeGen()(implicit ctx: Context) { val methodName: js.PropertyName = encodeMethodSym(sym) def jsParams = for (param <- params) yield { - implicit val pos: Position = param.pos + implicit val pos = param.pos js.ParamDef(encodeLocalSym(param), toIRType(param.info), mutable = false, rest = false) } @@ -574,13 +574,13 @@ class JSCodeGen()(implicit ctx: Context) { private def genMethodDef(static: Boolean, methodName: js.PropertyName, paramsSyms: List[Symbol], resultIRType: jstpe.Type, tree: Tree, optimizerHints: OptimizerHints): js.MethodDef = { - implicit val pos: Position = tree.pos + implicit val pos = tree.pos ctx.debuglog("genMethod " + methodName.name) ctx.debuglog("") val jsParams = for (param <- paramsSyms) yield { - implicit val pos: Position = param.pos + implicit val pos = param.pos js.ParamDef(encodeLocalSym(param), toIRType(param.info), mutable = false, rest = false) } @@ -621,7 +621,7 @@ class JSCodeGen()(implicit ctx: Context) { /* Any JavaScript expression is also a statement, but at least we get rid * of some pure expressions that come from our own codegen. */ - implicit val pos: Position = tree.pos + implicit val pos = tree.pos tree match { case js.Block(stats :+ expr) => js.Block(stats :+ exprToStat(expr)) case _:js.Literal | js.This() => js.Skip() @@ -644,7 +644,7 @@ class JSCodeGen()(implicit ctx: Context) { * is transformed into an equivalent portion of the JS AST. */ private def genStatOrExpr(tree: Tree, isStat: Boolean): js.Tree = { - implicit val pos: Position = tree.pos + implicit val pos = tree.pos ctx.debuglog(" " + tree) ctx.debuglog("") @@ -902,7 +902,7 @@ class JSCodeGen()(implicit ctx: Context) { * primitives, JS calls, etc. They are further dispatched in here. */ private def genApply(tree: Apply, isStat: Boolean): js.Tree = { - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val args = tree.args val sym = tree.fun.symbol @@ -951,7 +951,7 @@ class JSCodeGen()(implicit ctx: Context) { * irrelevant. */ private def genSuperCall(tree: Apply, isStat: Boolean): js.Tree = { - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val Apply(fun @ Select(sup @ Super(_, mix), _), args) = tree val sym = fun.symbol @@ -987,7 +987,7 @@ class JSCodeGen()(implicit ctx: Context) { * * regular new */ private def genApplyNew(tree: Apply): js.Tree = { - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val Apply(fun @ Select(New(tpt), nme.CONSTRUCTOR), args) = tree val ctor = fun.symbol @@ -1023,7 +1023,7 @@ class JSCodeGen()(implicit ctx: Context) { private def genPrimitiveOp(tree: Apply, isStat: Boolean): js.Tree = { import scala.tools.nsc.backend.ScalaPrimitives._ - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val Apply(fun, args) = tree val receiver = qualifierOf(fun) @@ -1063,7 +1063,7 @@ class JSCodeGen()(implicit ctx: Context) { private def genSimpleUnaryOp(tree: Apply, arg: Tree, code: Int): js.Tree = { import scala.tools.nsc.backend.ScalaPrimitives._ - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val genArg = genExpr(arg) val resultIRType = toIRType(tree.tpe) @@ -1118,7 +1118,7 @@ class JSCodeGen()(implicit ctx: Context) { } import OpTypes._ - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val lhsIRType = toIRType(lhs.tpe) val rhsIRType = toIRType(rhs.tpe) @@ -1374,7 +1374,7 @@ class JSCodeGen()(implicit ctx: Context) { */ private def genStringConcat(tree: Apply, receiver: Tree, args: List[Tree]): js.Tree = { - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val arg = args.head @@ -1401,7 +1401,7 @@ class JSCodeGen()(implicit ctx: Context) { /** Gen JS code for a call to Any.## */ private def genScalaHash(tree: Apply, receiver: Tree): js.Tree = { - implicit val pos: Position = tree.pos + implicit val pos = tree.pos genModuleApplyMethod(defn.ScalaRuntimeModule.requiredMethod(nme.hash_), List(genExpr(receiver))) @@ -1411,7 +1411,7 @@ class JSCodeGen()(implicit ctx: Context) { private def genArrayOp(tree: Tree, code: Int): js.Tree = { import scala.tools.nsc.backend.ScalaPrimitives._ - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val Apply(fun, args) = tree val arrayObj = qualifierOf(fun) @@ -1462,7 +1462,7 @@ class JSCodeGen()(implicit ctx: Context) { // common case for which there is no side-effect nor NPE genArg case _ => - implicit val pos: Position = tree.pos + implicit val pos = tree.pos /* TODO Check for a null receiver? * In theory, it's UB, but that decision should be left for link time. */ @@ -1474,7 +1474,7 @@ class JSCodeGen()(implicit ctx: Context) { private def genCoercion(tree: Apply, receiver: Tree, code: Int): js.Tree = { import scala.tools.nsc.backend.ScalaPrimitives._ - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val source = genExpr(receiver) @@ -1544,7 +1544,7 @@ class JSCodeGen()(implicit ctx: Context) { /** Gen a call to the special `throw` method. */ private def genThrow(tree: Apply, args: List[Tree]): js.Tree = { - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val exception = args.head val genException = genExpr(exception) js.Throw { @@ -1568,7 +1568,7 @@ class JSCodeGen()(implicit ctx: Context) { * * Regular method call */ private def genNormalApply(tree: Apply, isStat: Boolean): js.Tree = { - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val fun = tree.fun match { case fun: Ident => desugarIdent(fun).get @@ -1616,7 +1616,7 @@ class JSCodeGen()(implicit ctx: Context) { superIn: Option[Symbol] = None)( implicit pos: Position): js.Tree = { - implicit val pos: Position = tree.pos + implicit val pos = tree.pos def noSpread = !args.exists(_.isInstanceOf[js.JSSpread]) val argc = args.size // meaningful only for methods that don't have varargs @@ -1775,7 +1775,7 @@ class JSCodeGen()(implicit ctx: Context) { * primitive instead.) */ private def genTypeApply(tree: TypeApply): js.Tree = { - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val TypeApply(fun, targs) = tree @@ -1803,7 +1803,7 @@ class JSCodeGen()(implicit ctx: Context) { /** Gen JS code for a Java Seq literal. */ private def genJavaSeqLiteral(tree: JavaSeqLiteral): js.Tree = { - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val genElems = tree.elems.map(genExpr) val arrayType = toReferenceType(tree.tpe).asInstanceOf[jstpe.ArrayType] @@ -1852,7 +1852,7 @@ class JSCodeGen()(implicit ctx: Context) { * available in the `body`. */ private def genClosure(tree: Closure): js.Tree = { - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val Closure(env, call, functionalInterface) = tree val envSize = env.size @@ -1868,7 +1868,7 @@ class JSCodeGen()(implicit ctx: Context) { val allCaptureValues = qualifier :: env val (formalCaptures, actualCaptures) = allCaptureValues.map { value => - implicit val pos: Position = value.pos + implicit val pos = value.pos val formalIdent = value match { case Ident(name) => freshLocalIdent(name.toString) case This(_) => freshLocalIdent("this") @@ -1988,7 +1988,7 @@ class JSCodeGen()(implicit ctx: Context) { /** Gen JS code for an isInstanceOf test (for reference types only) */ private def genIsInstanceOf(tree: Tree, value: js.Tree, to: Type): js.Tree = { - implicit val pos: Position = tree.pos + implicit val pos = tree.pos val sym = to.widenDealias.typeSymbol if (sym == defn.ObjectClass) { @@ -2242,7 +2242,7 @@ class JSCodeGen()(implicit ctx: Context) { * to perform the conversion to js.Array, then wrap in a Spread * operator. */ - implicit val pos: Position = arg.pos + implicit val pos = arg.pos val jsArrayArg = genModuleApplyMethod( jsdefn.RuntimePackage_genTraversableOnce2jsArray, List(genExpr(arg))) @@ -2259,7 +2259,7 @@ class JSCodeGen()(implicit ctx: Context) { */ private def tryGenRepeatedParamAsJSArray(arg: Tree, handleNil: Boolean): Option[List[js.Tree]] = { - implicit val pos: Position = arg.pos + implicit val pos = arg.pos // Given a method `def foo(args: T*)` arg match { diff --git a/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala b/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala index 0027defa7..eb4da5400 100644 --- a/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala +++ b/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala @@ -125,7 +125,7 @@ class DottyPrimitives(ctx: Context) { /** Initialize the primitive map */ private def init: immutable.Map[Symbol, Int] = { - implicit val ctx: Context = this.ctx + implicit val ctx = this.ctx import core.Symbols.defn val primitives = new mutable.HashMap[Symbol, Int]() diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index c4b2b2122..20273eb85 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -1224,7 +1224,7 @@ object Trees { case AppliedTypeTree(tpt, args) => this(this(x, tpt), args) case PolyTypeTree(tparams, body) => - implicit val ctx: Context = localCtx + implicit val ctx = localCtx this(this(x, tparams), body) case ByNameTypeTree(result) => this(x, result) @@ -1237,13 +1237,13 @@ object Trees { case UnApply(fun, implicits, patterns) => this(this(this(x, fun), implicits), patterns) case tree @ ValDef(name, tpt, _) => - implicit val ctx: Context = localCtx + implicit val ctx = localCtx this(this(x, tpt), tree.rhs) case tree @ DefDef(name, tparams, vparamss, tpt, _) => - implicit val ctx: Context = localCtx + implicit val ctx = localCtx this(this((this(x, tparams) /: vparamss)(apply), tpt), tree.rhs) case TypeDef(name, rhs) => - implicit val ctx: Context = localCtx + implicit val ctx = localCtx this(x, rhs) case tree @ Template(constr, parents, self, _) => this(this(this(this(x, constr), parents), self), tree.body) diff --git a/compiler/src/dotty/tools/dotc/config/PathResolver.scala b/compiler/src/dotty/tools/dotc/config/PathResolver.scala index aa4d8aeb0..a98fc8110 100644 --- a/compiler/src/dotty/tools/dotc/config/PathResolver.scala +++ b/compiler/src/dotty/tools/dotc/config/PathResolver.scala @@ -143,7 +143,7 @@ object PathResolver { println(Defaults) } else { - implicit val ctx: Context = (new ContextBase).initialCtx // Dotty deviation: implicits need explicit type + implicit val ctx = (new ContextBase).initialCtx // Dotty deviation: implicits need explicit type val ArgsSummary(sstate, rest, errors) = ctx.settings.processArguments(args.toList, true) errors.foreach(println) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 8b7c28e19..e2bb0ac1a 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -75,7 +75,7 @@ trait SymDenotations { this: Context => def explainSym(msg: String) = explain(s"$msg\n defined = ${denot.definedPeriodsString}") if (denot.is(ValidForever) || denot.isRefinementClass) true else { - implicit val ctx: Context = this + implicit val ctx = this val initial = denot.initial if ((initial ne denot) || ctx.phaseId != initial.validFor.firstPhaseId) { ctx.withPhase(initial.validFor.firstPhaseId).traceInvalid(initial) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index f8c0cdac9..743220f55 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -16,7 +16,7 @@ import scala.util.control.NonFatal /** Provides methods to compare types. */ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { - implicit val ctx: Context = initctx + implicit val ctx = initctx val state = ctx.typerState import state.constraint @@ -156,7 +156,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { private def firstTry(tp1: Type, tp2: Type): Boolean = tp2 match { case tp2: NamedType => def compareNamed(tp1: Type, tp2: NamedType): Boolean = { - implicit val ctx: Context = this.ctx + implicit val ctx = this.ctx tp2.info match { case info2: TypeAlias => isSubType(tp1, info2.alias) case _ => tp1 match { diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 7e6620f8e..36139b1d8 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3378,7 +3378,7 @@ object Types { /** Map this function over given type */ def mapOver(tp: Type): Type = { - implicit val ctx: Context = this.ctx // Dotty deviation: implicits need explicit type + implicit val ctx = this.ctx // Dotty deviation: implicits need explicit type tp match { case tp: NamedType => if (stopAtStatic && tp.symbol.isStatic) tp diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala index 7fd50bfdc..c27644ad9 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala @@ -14,7 +14,7 @@ object MessageContainer { implicit class MessageContext(val c: Context) extends AnyVal { def shouldExplain(cont: MessageContainer): Boolean = { - implicit val ctx: Context = c + implicit val ctx = c cont.contained.explanation match { case "" => false case _ => ctx.settings.explain.value diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 5c880c7bd..7595e5f2e 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -575,7 +575,7 @@ object Erasure extends TypeTestsCasts{ val bridge = ctx.newSymbol(ctx.owner, nme.ANON_FUN, Flags.Synthetic | Flags.Method, sam.info) val bridgeCtx = ctx.withOwner(bridge) Closure(bridge, bridgeParamss => { - implicit val ctx: Context = bridgeCtx + implicit val ctx = bridgeCtx val List(bridgeParams) = bridgeParamss val rhs = Apply(meth, (bridgeParams, implParamTypes).zipped.map(adapt(_, _))) @@ -691,7 +691,7 @@ object Erasure extends TypeTestsCasts{ val bridgeCtx = ctx.withOwner(bridge) tpd.DefDef(bridge, { paramss: List[List[tpd.Tree]] => - implicit val ctx: Context = bridgeCtx + implicit val ctx = bridgeCtx val rhs = paramss.foldLeft(sel)((fun, vparams) => fun.tpe.widen match { diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index aa4eefe43..63547032e 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -129,7 +129,7 @@ class TreeChecker extends Phase with SymTransformer { try checker.typedExpr(ctx.compilationUnit.tpdTree)(checkingCtx) catch { case NonFatal(ex) => //TODO CHECK. Check that we are bootstrapped - implicit val ctx: Context = checkingCtx + implicit val ctx = checkingCtx println(i"*** error while checking ${ctx.compilationUnit} after phase ${checkingCtx.phase.prev} ***") throw ex } diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 11121e1f3..a3b4cb311 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -992,7 +992,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => val nestedCtx = ctx.fresh.setExploreTyperState { - implicit val ctx: Context = nestedCtx + implicit val ctx = nestedCtx isAsSpecificValueType(tp1, constrained(tp2).resultType) } case _ => // (3b) diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 3931fcaf4..09487570d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -189,7 +189,7 @@ object Inliner { if (!ctx.isAfterTyper) { val inlineCtx = ctx sym.updateAnnotation(LazyBodyAnnotation { _ => - implicit val ctx: Context = inlineCtx + implicit val ctx = inlineCtx ctx.withNoError(treeExpr(ctx))(makeInlineable) }) } diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index e02e90df1..4ca9f9e10 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -683,7 +683,7 @@ class Namer { typer: Typer => //println(i"completing type params of $sym in ${sym.owner}") nestedCtx = localContext(sym).setNewScope myTypeParams = { - implicit val ctx: Context = nestedCtx + implicit val ctx = nestedCtx val tparams = original.rhs match { case PolyTypeTree(tparams, _) => tparams case _ => Nil -- cgit v1.2.3 From e31a4856f1c35b889b775608836f7d6a6a4262d6 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 12 Dec 2016 12:40:51 +0100 Subject: Better diagnosis for cyclic references caused by implicit search Since we now allow to drop the explicit type of a local implicit val it can happen that this causes a cyclic reference, namely when the typechecking of the right-hand side involves an implicit search. It's unpractical and fragile to avoid this. Instead we give now a nice error message explaining the problem and how to fix it in source code. --- compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala | 8 +++++++- compiler/src/dotty/tools/dotc/typer/Namer.scala | 1 - tests/neg/implicitDefs.scala | 7 +++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index a18c83ff8..a066fc04a 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -46,7 +46,13 @@ object ErrorReporting { errorMsg(msg, cx.outer) } } else msg - errorMsg(ex.show, ctx) + + if (cycleSym.is(Implicit, butNot = Method) && cycleSym.owner.isTerm) + em"""cyclic reference involving implicit $cycleSym + |This happens when the right hand-side of $cycleSym's definition involves an implicit search. + |To avoid the error, give $cycleSym an explicit type.""" + else + errorMsg(ex.show, ctx) } def wrongNumberOfArgs(fntpe: Type, kind: String, expectedArgs: List[TypeParamInfo], actual: List[untpd.Tree], pos: Position)(implicit ctx: Context) = diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 4ca9f9e10..4bcdd5071 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1001,7 +1001,6 @@ class Namer { typer: Typer => def missingType(modifier: String) = { ctx.error(s"${modifier}type of implicit definition needs to be given explicitly", mdef.pos) sym.resetFlag(Implicit) - } if (sym is Implicit) mdef match { diff --git a/tests/neg/implicitDefs.scala b/tests/neg/implicitDefs.scala index 1489344c8..3ec9796e8 100644 --- a/tests/neg/implicitDefs.scala +++ b/tests/neg/implicitDefs.scala @@ -8,4 +8,11 @@ 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 + + def foo(implicit x: String) = 1 + + def bar() = { + implicit val x = foo + x + } } -- cgit v1.2.3 From e7e51781b4b6f2be3a4d79d2edd87f732dc8b8a9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 12 Dec 2016 13:05:32 +0100 Subject: Drop "Dotty deviation" messages that are no longer applicable. --- compiler/src/dotty/tools/dotc/config/PathResolver.scala | 2 +- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/PathResolver.scala b/compiler/src/dotty/tools/dotc/config/PathResolver.scala index a98fc8110..8df9a8c0e 100644 --- a/compiler/src/dotty/tools/dotc/config/PathResolver.scala +++ b/compiler/src/dotty/tools/dotc/config/PathResolver.scala @@ -143,7 +143,7 @@ object PathResolver { println(Defaults) } else { - implicit val ctx = (new ContextBase).initialCtx // Dotty deviation: implicits need explicit type + implicit val ctx = (new ContextBase).initialCtx val ArgsSummary(sstate, rest, errors) = ctx.settings.processArguments(args.toList, true) errors.foreach(println) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 36139b1d8..4dffc4542 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3378,7 +3378,7 @@ object Types { /** Map this function over given type */ def mapOver(tp: Type): Type = { - implicit val ctx = this.ctx // Dotty deviation: implicits need explicit type + implicit val ctx = this.ctx tp match { case tp: NamedType => if (stopAtStatic && tp.symbol.isStatic) tp diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ae6b719e4..4ce70c6af 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1638,7 +1638,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit tryInsertImplicitOnQualifier(tree, pt).getOrElse(fallBack) if (isApplyProto(pt)) tryImplicit - else tryEither(tryApply(_))((_, _) => tryImplicit) + else tryEither(tryApply(_))((_, _) => tryImplicit) } /** If this tree is a select node `qual.name`, try to insert an implicit conversion -- cgit v1.2.3 From 2082307f725b208393044ddb21df753a5329f8ac Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 12 Dec 2016 13:13:19 +0100 Subject: Fix neg test case Needed an // error annotation --- tests/neg/implicitDefs.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/neg/implicitDefs.scala b/tests/neg/implicitDefs.scala index 3ec9796e8..3bfe60434 100644 --- a/tests/neg/implicitDefs.scala +++ b/tests/neg/implicitDefs.scala @@ -12,7 +12,7 @@ object implicitDefs { def foo(implicit x: String) = 1 def bar() = { - implicit val x = foo + implicit val x = foo // error: cyclic reference x } } -- cgit v1.2.3 From 559e49317912ce52c51e295346cebcafbb69462d Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Tue, 13 Dec 2016 10:21:16 +0100 Subject: Add CyclicImplicitVal error to messages --- .../src/dotty/tools/dotc/reporting/diagnostic/messages.scala | 11 +++++++++++ compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala | 6 ++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 489165e56..ce3cb48ec 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -899,4 +899,15 @@ object messages { val msg = hl"trying to define package with same name as `$existing`" val explanation = "" } + + case class CyclicImplicitVal(cycleSym: Symbol)(implicit ctx: Context) + extends Message(34) { + val kind = "Cyclic Reference" + val msg = em"cyclic reference involving $cycleSym" + val explanation = + hl"""|This happens when the right hand-side of $cycleSym's definition + |involves an implicit search. + | + |To avoid the error, give $cycleSym an explicit type.""" + } } diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index a066fc04a..5709bfbf9 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -28,7 +28,7 @@ object ErrorReporting { def cyclicErrorMsg(ex: CyclicReference)(implicit ctx: Context) = { val cycleSym = ex.denot.symbol - def errorMsg(msg: String, cx: Context): String = + def errorMsg(msg: String, cx: Context): Message = if (cx.mode is Mode.InferringReturnType) { cx.tree match { case tree: untpd.ValOrDefDef => @@ -48,9 +48,7 @@ object ErrorReporting { } else msg if (cycleSym.is(Implicit, butNot = Method) && cycleSym.owner.isTerm) - em"""cyclic reference involving implicit $cycleSym - |This happens when the right hand-side of $cycleSym's definition involves an implicit search. - |To avoid the error, give $cycleSym an explicit type.""" + CyclicImplicitVal(cycleSym) else errorMsg(ex.show, ctx) } -- cgit v1.2.3 From bc869e74cb18ffdb4d42b59ad654f55403b9b6bd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 15 Dec 2016 15:43:09 +0100 Subject: Add CyclicImplicitVal error to messages (reverted from commit 559e49317912ce52c51e295346cebcafbb69462d) --- .../src/dotty/tools/dotc/reporting/diagnostic/messages.scala | 11 ----------- compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala | 6 ++++-- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index ce3cb48ec..489165e56 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -899,15 +899,4 @@ object messages { val msg = hl"trying to define package with same name as `$existing`" val explanation = "" } - - case class CyclicImplicitVal(cycleSym: Symbol)(implicit ctx: Context) - extends Message(34) { - val kind = "Cyclic Reference" - val msg = em"cyclic reference involving $cycleSym" - val explanation = - hl"""|This happens when the right hand-side of $cycleSym's definition - |involves an implicit search. - | - |To avoid the error, give $cycleSym an explicit type.""" - } } diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index 5709bfbf9..a066fc04a 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -28,7 +28,7 @@ object ErrorReporting { def cyclicErrorMsg(ex: CyclicReference)(implicit ctx: Context) = { val cycleSym = ex.denot.symbol - def errorMsg(msg: String, cx: Context): Message = + def errorMsg(msg: String, cx: Context): String = if (cx.mode is Mode.InferringReturnType) { cx.tree match { case tree: untpd.ValOrDefDef => @@ -48,7 +48,9 @@ object ErrorReporting { } else msg if (cycleSym.is(Implicit, butNot = Method) && cycleSym.owner.isTerm) - CyclicImplicitVal(cycleSym) + em"""cyclic reference involving implicit $cycleSym + |This happens when the right hand-side of $cycleSym's definition involves an implicit search. + |To avoid the error, give $cycleSym an explicit type.""" else errorMsg(ex.show, ctx) } -- cgit v1.2.3