From defbe7dbcd81c1ec699e2ffb38fd4759ca74f08f Mon Sep 17 00:00:00 2001 From: Enno Runne Date: Wed, 15 Feb 2017 23:44:13 +0100 Subject: [PATCH 01/14] Change 'mixed left- and right-associative operators' to Message --- .../dotty/tools/dotc/parsing/Parsers.scala | 15 ++++----- .../dotc/reporting/diagnostic/messages.scala | 33 +++++++++++++++++++ .../dotc/reporting/ErrorMessagesTests.scala | 23 +++++++++++++ 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 45ae842b6021..8f146e92081b 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -404,14 +404,13 @@ object Parsers { var opStack: List[OpInfo] = Nil - def checkAssoc(offset: Int, op: Name, leftAssoc: Boolean) = + def checkAssoc(offset: Int, op: Name, leftAssoc: Boolean, op2: Name) = if (isLeftAssoc(op) != leftAssoc) - syntaxError( - "left- and right-associative operators with same precedence may not be mixed", offset) + syntaxError(MixedLeftAndRightAssociativeOps(op, op2, leftAssoc), offset) - def reduceStack(base: List[OpInfo], top: Tree, prec: Int, leftAssoc: Boolean): Tree = { + def reduceStack(base: List[OpInfo], top: Tree, prec: Int, leftAssoc: Boolean, op2: Name): Tree = { if (opStack != base && precedence(opStack.head.operator.name) == prec) - checkAssoc(opStack.head.offset, opStack.head.operator.name, leftAssoc) + checkAssoc(opStack.head.offset, opStack.head.operator.name, leftAssoc, op2) def recur(top: Tree): Tree = { if (opStack == base) top else { @@ -445,20 +444,20 @@ object Parsers { var top = first while (isIdent && in.name != notAnOperator) { val op = if (isType) typeIdent() else termIdent() - top = reduceStack(base, top, precedence(op.name), isLeftAssoc(op.name)) + top = reduceStack(base, top, precedence(op.name), isLeftAssoc(op.name), op.name) opStack = OpInfo(top, op, in.offset) :: opStack newLineOptWhenFollowing(canStartOperand) if (maybePostfix && !canStartOperand(in.token)) { val topInfo = opStack.head opStack = opStack.tail - val od = reduceStack(base, topInfo.operand, 0, true) + val od = reduceStack(base, topInfo.operand, 0, true, in.name) return atPos(startOffset(od), topInfo.offset) { PostfixOp(od, topInfo.operator) } } top = operand() } - reduceStack(base, top, 0, true) + reduceStack(base, top, 0, true, in.name) } /* -------- IDENTIFIERS AND LITERALS ------------------------------------------- */ diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 94611e10d014..c8916bb6e634 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1086,4 +1086,37 @@ object messages { |""".stripMargin } + case class MixedLeftAndRightAssociativeOps(op1: Name, op2: Name, op2LeftAssoc: Boolean)(implicit ctx: Context) + extends Message(41) { + val kind = "Syntax" + val op1Asso = if (op2LeftAssoc) "which is right-associative" else "which is left-associative" + val op2Asso = if (op2LeftAssoc) "which is left-associative" else "which is right-associative" + val msg = s"${hl"`${op1}`"} (${op1Asso}) and ${hl"`${op2}`"} ($op2Asso) have same precedence and may not be mixed" + val explanation = + s"""|The operators ${hl"${op1}"} and ${hl"${op2}"} are used as infix operators in the same expression, + |but they bind to different sides: + |${hl"${op1}"} is applied to the operand to its ${if (op2LeftAssoc) "right" else "left"} + |${hl"${op2}"} is applied to the operand to its ${if (op2LeftAssoc) "left" else "right"} + |As both have the same precedence the compiler can't decide which to apply first. + | + |You may use parenthesis to make the application order explicit, + |or use method application syntax ${hl"`operand1.${op1}(operand2)`"}. + | + |Operators ending in a colon `:` are right-associative. All other operators are left-associative. + | + |Infix operator precedence is determined by the operator's first character: + | (all letters) + | | + | ^ + | & + | = ! + | < > + | : + | + - + | * / % + | (all other special characters) + |Operators starting with a letter have lowest precedence, followed by operators starting with `|', etc. + |""".stripMargin + } + } diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index 697a00510e06..37d1404bb278 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -136,4 +136,27 @@ class ErrorMessagesTests extends ErrorMessagesTest { """.stripMargin } .expectNoErrors + + @Test def leftAndRightAssociative = + checkMessagesAfter("frontend") { + """ + |object Ops { + | case class I(j: Int) { + | def +-(i: Int) = i + | def +:(i: Int) = i + | } + | val v = I(1) +- I(4) +: I(4) + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + val defn = ictx.definitions + + assertMessageCount(1, messages) + val MixedLeftAndRightAssociativeOps(op1, op2, op2LeftAssoc) :: Nil = messages + assertEquals("+-", op1.show) + assertEquals("+:", op2.show) + assertFalse(op2LeftAssoc) + } } From dcf7877d22baed92f488f7cb3561b4fa13339127 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 9 Feb 2017 14:45:42 +0100 Subject: [PATCH 02/14] Add checks for synthetic functions and erased functions. * Add `isSyntheticFunction` checks for synthetic functions such as FuntionN for N > 22 and ImplicitFunctionN for N >= 0. * Add `erasedFunctionClass` to get the erased verion of synthetic functions. * Change the semantics of `isFunctionClass` to return true if it is any kind of FunctionN or ImplicitFunctionN. --- .../dotty/tools/dotc/core/Definitions.scala | 90 +++++++++++++------ .../src/dotty/tools/dotc/core/NameOps.scala | 45 ++++++++-- .../dotty/tools/dotc/core/TypeErasure.scala | 11 ++- .../tools/dotc/printing/RefinedPrinter.scala | 3 +- .../dotty/tools/dotc/transform/Erasure.scala | 6 +- .../tools/dotc/transform/TreeChecker.scala | 2 +- .../src/dotty/tools/dotc/typer/Typer.scala | 6 +- 7 files changed, 111 insertions(+), 52 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 01a164a812d9..9e9e39a8439d 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -637,13 +637,9 @@ class Definitions { FunctionType(args.length, isImplicit).appliedTo(args ::: resultType :: Nil) def unapply(ft: Type)(implicit ctx: Context) = { val tsym = ft.typeSymbol - val isImplicitFun = isImplicitFunctionClass(tsym) - if (isImplicitFun || isFunctionClass(tsym)) { - val targs = ft.argInfos - val numArgs = targs.length - 1 - if (numArgs >= 0 && FunctionType(numArgs, isImplicitFun).symbol == tsym) - Some(targs.init, targs.last, isImplicitFun) - else None + if (isFunctionClass(tsym)) { + val targs = ft.dealias.argInfos + Some(targs.init, targs.last, tsym.name.isImplicitFunction) } else None } @@ -696,20 +692,17 @@ class Definitions { lazy val TupleType = mkArityArray("scala.Tuple", MaxTupleArity, 2) lazy val ProductNType = mkArityArray("scala.Product", MaxTupleArity, 0) - def FunctionClass(n: Int)(implicit ctx: Context) = - if (n < MaxImplementedFunctionArity) FunctionClassPerRun()(ctx)(n) + def FunctionClass(n: Int, isImplicit: Boolean = false)(implicit ctx: Context) = + if (isImplicit) ctx.requiredClass("scala.ImplicitFunction" + n.toString) + else if (n <= MaxImplementedFunctionArity) FunctionClassPerRun()(ctx)(n) else ctx.requiredClass("scala.Function" + n.toString) lazy val Function0_applyR = ImplementedFunctionType(0).symbol.requiredMethodRef(nme.apply) def Function0_apply(implicit ctx: Context) = Function0_applyR.symbol - def ImplicitFunctionClass(n: Int)(implicit ctx: Context) = - ctx.requiredClass("scala.ImplicitFunction" + n.toString) - def FunctionType(n: Int, isImplicit: Boolean = false)(implicit ctx: Context): TypeRef = - if (isImplicit && !ctx.erasedTypes) ImplicitFunctionClass(n).typeRef - else if (n < MaxImplementedFunctionArity) ImplementedFunctionType(n) - else FunctionClass(n).typeRef + if (n <= MaxImplementedFunctionArity && (!isImplicit || ctx.erasedTypes)) ImplementedFunctionType(n) + else FunctionClass(n, isImplicit).typeRef private lazy val TupleTypes: Set[TypeRef] = TupleType.toSet private lazy val ProductTypes: Set[TypeRef] = ProductNType.toSet @@ -733,14 +726,61 @@ class Definitions { def isBottomType(tp: Type) = tp.derivesFrom(NothingClass) || tp.derivesFrom(NullClass) - def isFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.Function) - def isImplicitFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.ImplicitFunction) - /** Is a class that will be erased to FunctionXXL */ - def isXXLFunctionClass(cls: Symbol) = cls.name.functionArity > MaxImplementedFunctionArity + /** Is a function class. + * - FunctionN for N >= 0 + * - ImplicitFunctionN for N >= 0 + */ + def isFunctionClass(cls: Symbol) = scalaClassName(cls).isFunction + + /** Is an implicit function class. + * - ImplicitFunctionN for N >= 0 + */ + def isImplicitFunctionClass(cls: Symbol) = scalaClassName(cls).isImplicitFunction + + /** Is a class that will be erased to FunctionXXL + * - FunctionN for N >= 22 + * - ImplicitFunctionN for N >= 22 + */ + def isXXLFunctionClass(cls: Symbol) = scalaClassName(cls).functionArity > MaxImplementedFunctionArity + + /** Is a synthetic function class + * - FunctionN for N > 22 + * - ImplicitFunctionN for N >= 0 + */ + def isSyntheticFunctionClass(cls: Symbol) = scalaClassName(cls).isSyntheticFunction + def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.AbstractFunction) def isTupleClass(cls: Symbol) = isVarArityClass(cls, tpnme.Tuple) def isProductClass(cls: Symbol) = isVarArityClass(cls, tpnme.Product) + /** Returns the erased class of the function class `cls` + * - FunctionN for N > 22 becomes FunctionXXL + * - FunctionN for 22 > N >= 0 remains as FunctionN + * - ImplicitFunctionN for N > 22 becomes FunctionXXL + * - ImplicitFunctionN for 22 > N >= 0 becomes FunctionN + * - anything else becomes a NoSymbol + */ + def erasedFunctionClass(cls: Symbol): Symbol = { + val arity = scalaClassName(cls).functionArity + if (arity > 22) defn.FunctionXXLClass + else if (arity >= 0) defn.FunctionClass(arity) + else NoSymbol + } + + /** Returns the erased type of the function class `cls` + * - FunctionN for N > 22 becomes FunctionXXL + * - FunctionN for 22 > N >= 0 remains as FunctionN + * - ImplicitFunctionN for N > 22 becomes FunctionXXL + * - ImplicitFunctionN for 22 > N >= 0 becomes FunctionN + * - anything else becomes a NoType + */ + def erasedFunctionType(cls: Symbol): Type = { + val arity = scalaClassName(cls).functionArity + if (arity > 22) defn.FunctionXXLType + else if (arity >= 0) defn.FunctionType(arity) + else NoType + } + val predefClassNames: Set[Name] = Set("Predef$", "DeprecatedPredef", "LowPriorityImplicits").map(_.toTypeName) @@ -811,16 +851,13 @@ class Definitions { def isFunctionType(tp: Type)(implicit ctx: Context) = { val arity = functionArity(tp) val sym = tp.dealias.typeSymbol - arity >= 0 && ( - isFunctionClass(sym) && tp.isRef(FunctionType(arity, isImplicit = false).typeSymbol) || - isImplicitFunctionClass(sym) && tp.isRef(FunctionType(arity, isImplicit = true).typeSymbol) - ) + arity >= 0 && isFunctionClass(sym) && tp.isRef(FunctionType(arity, sym.name.isImplicitFunction).typeSymbol) } def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1 def isImplicitFunctionType(tp: Type)(implicit ctx: Context) = - isFunctionType(tp) && tp.dealias.typeSymbol.name.startsWith(tpnme.ImplicitFunction) + isFunctionType(tp) && tp.dealias.typeSymbol.name.isImplicitFunction // ----- primitive value class machinery ------------------------------------------ @@ -894,9 +931,6 @@ class Definitions { // ----- Initialization --------------------------------------------------- - private def maxImplemented(name: Name) = - if (name `startsWith` tpnme.Function) MaxImplementedFunctionArity else 0 - /** Give the scala package a scope where a FunctionN trait is automatically * added when someone looks for it. */ @@ -906,7 +940,7 @@ class Definitions { val newDecls = new MutableScope(oldDecls) { override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { val res = super.lookupEntry(name) - if (res == null && name.isTypeName && name.functionArity > maxImplemented(name)) + if (res == null && name.isTypeName && name.isSyntheticFunction) newScopeEntry(newFunctionNTrait(name.asTypeName)) else res } diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index c037d1ce7d12..cd3ae2a25632 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -8,6 +8,7 @@ import Names._, StdNames._, Contexts._, Symbols._, Flags._ import Decorators.StringDecorator import util.{Chars, NameTransformer} import Chars.isOperatorPart +import Definitions._ object NameOps { @@ -231,13 +232,43 @@ object NameOps { } } - def functionArity: Int = { - def test(prefix: Name): Int = - if (name.startsWith(prefix)) - try name.drop(prefix.length).toString.toInt - catch { case ex: NumberFormatException => -1 } - else -1 - test(tpnme.Function) max test(tpnme.ImplicitFunction) + /** Is a synthetic function name + * - N for FunctionN + * - N for ImplicitFunctionN + * - (-1) otherwise + */ + def functionArity: Int = + functionArityFor(tpnme.Function) max functionArityFor(tpnme.ImplicitFunction) + + /** Is a function name + * - FunctionN for N >= 0 + * - ImplicitFunctionN for N >= 0 + * - false otherwise + */ + def isFunction: Boolean = functionArity >= 0 + + /** Is a implicit function name + * - ImplicitFunctionN for N >= 0 + * - false otherwise + */ + def isImplicitFunction: Boolean = functionArityFor(tpnme.ImplicitFunction) >= 0 + + /** Is a synthetic function name + * - FunctionN for N > 22 + * - ImplicitFunctionN for N >= 0 + * - false otherwise + */ + def isSyntheticFunction: Boolean = { + functionArityFor(tpnme.Function) > MaxImplementedFunctionArity || + functionArityFor(tpnme.ImplicitFunction) >= 0 + } + + /** Parsed function arity for function with some specific prefix */ + private def functionArityFor(prefix: Name): Int = { + if (name.startsWith(prefix)) + try name.toString.substring(prefix.length).toInt + catch { case _: NumberFormatException => -1 } + else -1 } /** The name of the generic runtime operation corresponding to an array operation */ diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 2a341390b5d2..ff99008bbf61 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -44,7 +44,7 @@ object TypeErasure { val sym = tp.symbol sym.isClass && sym != defn.AnyClass && sym != defn.ArrayClass && - !defn.isXXLFunctionClass(sym) && !defn.isImplicitFunctionClass(sym) + !defn.isSyntheticFunctionClass(sym) case _: TermRef => true case JavaArrayType(elem) => @@ -358,8 +358,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean if (!sym.isClass) this(tp.info) else if (semiEraseVCs && isDerivedValueClass(sym)) eraseDerivedValueClassRef(tp) else if (sym == defn.ArrayClass) apply(tp.appliedTo(TypeBounds.empty)) // i966 shows that we can hit a raw Array type. - else if (defn.isXXLFunctionClass(sym)) defn.FunctionXXLType - else if (defn.isImplicitFunctionClass(sym)) apply(defn.FunctionType(sym.name.functionArity)) + else if (defn.isSyntheticFunctionClass(sym)) defn.erasedFunctionType(sym) else eraseNormalClassRef(tp) case tp: RefinedType => val parent = tp.parent @@ -370,7 +369,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean case SuperType(thistpe, supertpe) => SuperType(this(thistpe), this(supertpe)) case ExprType(rt) => - defn.FunctionClass(0).typeRef + defn.FunctionType(0) case AndType(tp1, tp2) => erasedGlb(this(tp1), this(tp2), isJava) case OrType(tp1, tp2) => @@ -496,8 +495,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean val erasedVCRef = eraseDerivedValueClassRef(tp) if (erasedVCRef.exists) return sigName(erasedVCRef) } - if (defn.isImplicitFunctionClass(sym)) - sigName(defn.FunctionType(sym.name.functionArity)) + if (defn.isSyntheticFunctionClass(sym)) + sigName(defn.erasedFunctionType(sym)) else normalizeClass(sym.asClass).fullName.asTypeName case defn.ArrayOf(elem) => diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 5b75df6b26f7..3d952f425e9c 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -126,8 +126,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case AppliedType(tycon, args) => val cls = tycon.typeSymbol if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ "*" - if (defn.isFunctionClass(cls)) return toTextFunction(args, isImplicit = false) - if (defn.isImplicitFunctionClass(cls)) return toTextFunction(args, isImplicit = true) + if (defn.isFunctionClass(cls)) return toTextFunction(args, cls.name.isImplicitFunction) if (defn.isTupleClass(cls)) return toTextTuple(args) return (toTextLocal(tycon) ~ "[" ~ Text(args map argText, ", ") ~ "]").close case tp: TypeRef => diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index bba97c4c206d..34ea2bc6fa8f 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -349,10 +349,8 @@ object Erasure extends TypeTestsCasts{ if ((owner eq defn.AnyClass) || (owner eq defn.AnyValClass)) { assert(sym.isConstructor, s"${sym.showLocated}") defn.ObjectClass - } else if (defn.isXXLFunctionClass(owner)) - defn.FunctionXXLClass - else if (defn.isImplicitFunctionClass(owner)) - recur(defn.FunctionClass(owner.name.functionArity)) + } else if (defn.isSyntheticFunctionClass(owner)) + defn.erasedFunctionClass(owner) else owner recur(sym.owner) diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index eee429a87e3c..b2b99160b35c 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -81,7 +81,7 @@ class TreeChecker extends Phase with SymTransformer { val sym = symd.symbol if (sym.isClass && !sym.isAbsent) { - val validSuperclass = sym.isPrimitiveValueClass || defn.syntheticCoreClasses.contains(sym) || + val validSuperclass = sym.isPrimitiveValueClass || defn.syntheticCoreClasses.contains(sym) || (sym eq defn.ObjectClass) || (sym is NoSuperClass) || (sym.asClass.superClass.exists) if (!validSuperclass) printError(s"$sym has no superclass set") diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 52f0a7ec7595..2b57cf778596 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -669,9 +669,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedFunction(tree: untpd.Function, pt: Type)(implicit ctx: Context) = track("typedFunction") { val untpd.Function(args, body) = tree if (ctx.mode is Mode.Type) { - val funCls = - if (tree.isInstanceOf[untpd.ImplicitFunction]) defn.ImplicitFunctionClass(args.length) - else defn.FunctionClass(args.length) + val funCls = defn.FunctionClass(args.length, tree.isInstanceOf[untpd.ImplicitFunction]) typed(cpy.AppliedTypeTree(tree)( untpd.TypeTree(funCls.typeRef), args :+ body), pt) } @@ -1942,7 +1940,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit !untpd.isImplicitClosure(tree) && !isApplyProto(pt) && !ctx.isAfterTyper) { - typr.println("insert apply on implicit $tree") + typr.println(i"insert apply on implicit $tree") typed(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt) } else if (ctx.mode is Mode.Pattern) { From 85dae44d1eb5948668e5afe01c127b5de23ed0be Mon Sep 17 00:00:00 2001 From: Enno Runne Date: Thu, 16 Feb 2017 21:11:16 +0100 Subject: [PATCH 03/14] Incorporated comments from @felixmulder --- .../src/dotty/tools/dotc/parsing/Parsers.scala | 8 ++++---- .../dotc/reporting/diagnostic/messages.scala | 15 ++++++++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 8f146e92081b..b46bc401da68 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -404,13 +404,13 @@ object Parsers { var opStack: List[OpInfo] = Nil - def checkAssoc(offset: Int, op: Name, leftAssoc: Boolean, op2: Name) = - if (isLeftAssoc(op) != leftAssoc) - syntaxError(MixedLeftAndRightAssociativeOps(op, op2, leftAssoc), offset) + def checkAssoc(offset: Token, op1: Name, op2: Name, op2LeftAssoc: Boolean): Unit = + if (isLeftAssoc(op1) != op2LeftAssoc) + syntaxError(MixedLeftAndRightAssociativeOps(op1, op2, op2LeftAssoc), offset) def reduceStack(base: List[OpInfo], top: Tree, prec: Int, leftAssoc: Boolean, op2: Name): Tree = { if (opStack != base && precedence(opStack.head.operator.name) == prec) - checkAssoc(opStack.head.offset, opStack.head.operator.name, leftAssoc, op2) + checkAssoc(opStack.head.offset, opStack.head.operator.name, op2, leftAssoc) def recur(top: Tree): Tree = { if (opStack == base) top else { diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index c8916bb6e634..962d500c3926 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1091,20 +1091,21 @@ object messages { val kind = "Syntax" val op1Asso = if (op2LeftAssoc) "which is right-associative" else "which is left-associative" val op2Asso = if (op2LeftAssoc) "which is left-associative" else "which is right-associative" - val msg = s"${hl"`${op1}`"} (${op1Asso}) and ${hl"`${op2}`"} ($op2Asso) have same precedence and may not be mixed" + val msg = s"`${op1}` (${op1Asso}) and `${op2}` ($op2Asso) have same precedence and may not be mixed" val explanation = - s"""|The operators ${hl"${op1}"} and ${hl"${op2}"} are used as infix operators in the same expression, + s"""|The operators ${op1} and ${op2} are used as infix operators in the same expression, |but they bind to different sides: - |${hl"${op1}"} is applied to the operand to its ${if (op2LeftAssoc) "right" else "left"} - |${hl"${op2}"} is applied to the operand to its ${if (op2LeftAssoc) "left" else "right"} + |${op1} is applied to the operand to its ${if (op2LeftAssoc) "right" else "left"} + |${op2} is applied to the operand to its ${if (op2LeftAssoc) "left" else "right"} |As both have the same precedence the compiler can't decide which to apply first. | |You may use parenthesis to make the application order explicit, - |or use method application syntax ${hl"`operand1.${op1}(operand2)`"}. + |or use method application syntax `operand1.${op1}(operand2)`. | |Operators ending in a colon `:` are right-associative. All other operators are left-associative. | - |Infix operator precedence is determined by the operator's first character: + |Infix operator precedence is determined by the operator's first character. Characters are listed + |below in increasing order of precedence, with characters on the same line having the same precedence. | (all letters) | | | ^ @@ -1115,7 +1116,7 @@ object messages { | + - | * / % | (all other special characters) - |Operators starting with a letter have lowest precedence, followed by operators starting with `|', etc. + |Operators starting with a letter have lowest precedence, followed by operators starting with `|`, etc. |""".stripMargin } From 835d24f81efcce8389a94817c480a9bca36ad9c3 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Mon, 13 Feb 2017 04:04:21 +0100 Subject: [PATCH 04/14] TreeMap/TreeAccumulator: proper context for inlined trees This was already be done in TreeTraverser but should also be done in TreeMap and TreeAccumulator for ctx.error(..., tree.pos) to not use completely incorrect positions inside inlined trees. --- compiler/src/dotty/tools/dotc/ast/Trees.scala | 11 +++++++++-- compiler/src/dotty/tools/dotc/ast/tpd.scala | 5 +---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index bf11a442e515..27be8c9d6b22 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -1077,6 +1077,13 @@ object Trees { /** Hook to indicate that a transform of some subtree should be skipped */ protected def skipTransform(tree: Tree)(implicit ctx: Context): Boolean = false + /** For untyped trees, this is just the identity. + * For typed trees, a context derived form `ctx` that records `call` as the + * innermost enclosing call for which the inlined version is currently + * processed. + */ + protected def inlineContext(call: Tree)(implicit ctx: Context): Context = ctx + abstract class TreeMap(val cpy: TreeCopier = inst.cpy) { def transform(tree: Tree)(implicit ctx: Context): Tree = @@ -1121,7 +1128,7 @@ object Trees { case SeqLiteral(elems, elemtpt) => cpy.SeqLiteral(tree)(transform(elems), transform(elemtpt)) case Inlined(call, bindings, expansion) => - cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)) + cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(inlineContext(call))) case TypeTree() => tree case SingletonTypeTree(ref) => @@ -1225,7 +1232,7 @@ object Trees { case SeqLiteral(elems, elemtpt) => this(this(x, elems), elemtpt) case Inlined(call, bindings, expansion) => - this(this(x, bindings), expansion) + this(this(x, bindings), expansion)(inlineContext(call)) case TypeTree() => x case SingletonTypeTree(ref) => diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index ed268fda7326..d1d886c5550f 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -933,10 +933,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { /** A key to be used in a context property that tracks enclosing inlined calls */ private val InlinedCalls = new Property.Key[List[Tree]] - /** A context derived form `ctx` that records `call` as innermost enclosing - * call for which the inlined version is currently processed. - */ - def inlineContext(call: Tree)(implicit ctx: Context): Context = + override def inlineContext(call: Tree)(implicit ctx: Context): Context = ctx.fresh.setProperty(InlinedCalls, call :: enclosingInlineds) /** All enclosing calls that are currently inlined, from innermost to outermost */ From 16b25a71ec34b6e381dc5e44be3b382c1c35d2d9 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 16 Feb 2017 10:59:29 +0100 Subject: [PATCH 05/14] Use enum for error messages IDs. --- .../dotc/reporting/MessageRendering.scala | 9 +- .../reporting/diagnostic/ErrorMessageID.java | 57 ++++++++++++ .../dotc/reporting/diagnostic/Message.scala | 9 +- .../dotc/reporting/diagnostic/messages.scala | 91 ++++++++++--------- .../dotc/reporting/TestMessageLaziness.scala | 6 +- 5 files changed, 116 insertions(+), 56 deletions(-) create mode 100644 compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index 24d583b19fe7..190445d60171 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -5,7 +5,7 @@ package reporting import core.Contexts.Context import core.Decorators._ import printing.Highlighting.{Blue, Red} -import diagnostic.{Message, MessageContainer, NoExplanation} +import diagnostic.{ErrorMessageID, Message, MessageContainer, NoExplanation} import diagnostic.messages._ import util.SourcePosition @@ -95,9 +95,10 @@ trait MessageRendering { if (pos.exists) Blue({ val file = pos.source.file.toString val errId = - if (message.errorId != NoExplanation.ID) - s"[E${"0" * (3 - message.errorId.toString.length) + message.errorId}] " - else "" + if (message.errorId ne ErrorMessageID.NoExplanationID) { + val errorNumber = message.errorId.errorNumber() + s"[E${"0" * (3 - errorNumber.toString.length) + errorNumber}] " + } else "" val kind = if (message.kind == "") diagnosticLevel else s"${message.kind} $diagnosticLevel" diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java new file mode 100644 index 000000000000..43930a56e0f1 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java @@ -0,0 +1,57 @@ +package dotty.tools.dotc.reporting.diagnostic; + +/** Unique IDs identifying the messages */ +public enum ErrorMessageID { + + // IMPORTANT: Add new IDs only at the end and never remove IDs + + LazyErrorId, // // errorNumber: -2 + NoExplanationID, // errorNumber: -1 + + EmptyCatchOrFinallyBlockID, // errorNumber: 0 + EmptyCatchBlockID, // errorNumber: 1 + EmptyCatchAndFinallyBlockID, // errorNumber: 2 + DeprecatedWithOperatorID, + CaseClassMissingParamListID, + DuplicateBindID, + MissingIdentID, + TypeMismatchID, + NotAMemberID, + EarlyDefinitionsNotSupportedID, + TopLevelImplicitClassID, + ImplicitCaseClassID, + ObjectMayNotHaveSelfTypeID, + TupleTooLongID, + RepeatedModifierID, + InterpolatedStringErrorID, + UnboundPlaceholderParameterID, + IllegalStartSimpleExprID, + MissingReturnTypeID, + YieldOrDoExpectedInForComprehensionID, + ProperDefinitionNotFoundID, + ByNameParameterNotSupportedID, + WrongNumberOfTypeArgsID, + IllegalVariableInPatternAlternativeID, + TypeParamsTypeExpectedID, + IdentifierExpectedID, + AuxConstructorNeedsNonImplicitParameterID, + IncorrectRepeatedParameterSyntaxID, + IllegalLiteralID, + PatternMatchExhaustivityID, + MatchCaseUnreachableID, + SeqWildcardPatternPosID, + IllegalStartOfSimplePatternID, + PkgDuplicateSymbolID, + ExistentialTypesNoLongerSupportedID, + UnboundWildcardTypeID, + DanglingThisInPathID, + OverridesNothingID, + OverridesNothingButNameExistsID, + ForwardReferenceExtendsOverDefinitionID, + ExpectedTokenButFoundID; + + public int errorNumber() { + return ordinal() - 2; + } + +} diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala index ab1222dab6b7..09d7ae9751be 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala @@ -30,11 +30,10 @@ object Message { * Instead use the `persist` method to create an instance that does not keep a * reference to these contexts. * - * @param errorId a unique number identifying the message, this will later be + * @param errorId a unique id identifying the message, this will later be * used to reference documentation online */ -abstract class Message(val errorId: Int) { self => - import messages._ +abstract class Message(val errorId: ErrorMessageID) { self => /** The `msg` contains the diagnostic message e.g: * @@ -116,7 +115,7 @@ class ExtendMessage(_msg: () => Message)(f: String => String) { self => } /** The fallback `Message` containing no explanation and having no `kind` */ -class NoExplanation(val msg: String) extends Message(NoExplanation.ID) { +class NoExplanation(val msg: String) extends Message(ErrorMessageID.NoExplanationID) { val explanation = "" val kind = "" @@ -127,8 +126,6 @@ class NoExplanation(val msg: String) extends Message(NoExplanation.ID) { * lacks an explanation */ object NoExplanation { - final val ID = -1 - def unapply(m: Message): Option[Message] = if (m.explanation == "") Some(m) else None diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 962d500c3926..ed1c5642f331 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -17,6 +17,7 @@ import dotc.parsing.Scanners.Token import dotc.parsing.Tokens import printing.Highlighting._ import printing.Formatting +import ErrorMessageID._ object messages { @@ -94,8 +95,8 @@ object messages { // Syntax Errors ---------------------------------------------------------- // - abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree, errNo: Int)(implicit ctx: Context) - extends Message(errNo) { + abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree, errNo: ErrorMessageID)(implicit ctx: Context) + extends Message(EmptyCatchOrFinallyBlockID) { val explanation = { val tryString = tryBody match { case Block(Nil, untpd.EmptyTree) => "{}" @@ -131,7 +132,7 @@ object messages { } case class EmptyCatchBlock(tryBody: untpd.Tree)(implicit ctx: Context) - extends EmptyCatchOrFinallyBlock(tryBody, 1) { + extends EmptyCatchOrFinallyBlock(tryBody, EmptyCatchBlockID) { val kind = "Syntax" val msg = hl"""|The ${"catch"} block does not contain a valid expression, try @@ -139,7 +140,7 @@ object messages { } case class EmptyCatchAndFinallyBlock(tryBody: untpd.Tree)(implicit ctx: Context) - extends EmptyCatchOrFinallyBlock(tryBody, 2) { + extends EmptyCatchOrFinallyBlock(tryBody, EmptyCatchAndFinallyBlockID) { val kind = "Syntax" val msg = hl"""|A ${"try"} without ${"catch"} or ${"finally"} is equivalent to putting @@ -147,7 +148,7 @@ object messages { } case class DeprecatedWithOperator()(implicit ctx: Context) - extends Message(3) { + extends Message(DeprecatedWithOperatorID) { val kind = "Syntax" val msg = hl"""${"with"} as a type operator has been deprecated; use `&' instead""" @@ -158,7 +159,7 @@ object messages { } case class CaseClassMissingParamList(cdef: untpd.TypeDef)(implicit ctx: Context) - extends Message(4) { + extends Message(CaseClassMissingParamListID) { val kind = "Syntax" val msg = hl"""|A ${"case class"} must have at least one parameter list""" @@ -172,7 +173,7 @@ object messages { // Type Errors ------------------------------------------------------------ // case class DuplicateBind(bind: untpd.Bind, tree: untpd.CaseDef)(implicit ctx: Context) - extends Message(5) { + extends Message(DuplicateBindID) { val kind = "Naming" val msg = em"duplicate pattern variable: `${bind.name}`" @@ -199,7 +200,7 @@ object messages { } case class MissingIdent(tree: untpd.Ident, treeKind: String, name: String)(implicit ctx: Context) - extends Message(6) { + extends Message(MissingIdentID) { val kind = "Unbound Identifier" val msg = em"not found: $treeKind$name" @@ -212,7 +213,7 @@ object messages { } case class TypeMismatch(found: Type, expected: Type, whyNoMatch: String = "", implicitFailure: String = "")(implicit ctx: Context) - extends Message(7) { + extends Message(TypeMismatchID) { val kind = "Type Mismatch" val msg = { val (where, printCtx) = Formatting.disambiguateTypes(found, expected) @@ -227,7 +228,7 @@ object messages { } case class NotAMember(site: Type, name: Name, selected: String)(implicit ctx: Context) - extends Message(8) { + extends Message(NotAMemberID) { val kind = "Member Not Found" //println(i"site = $site, decls = ${site.decls}, source = ${site.widen.typeSymbol.sourceFile}") //DEBUG @@ -293,7 +294,7 @@ object messages { } case class EarlyDefinitionsNotSupported()(implicit ctx: Context) - extends Message(9) { + extends Message(EarlyDefinitionsNotSupportedID) { val kind = "Syntax" val msg = "early definitions are not supported; use trait parameters instead" @@ -339,7 +340,7 @@ object messages { } case class TopLevelImplicitClass(cdef: untpd.TypeDef)(implicit ctx: Context) - extends Message(10) { + extends Message(TopLevelImplicitClassID) { val kind = "Syntax" val msg = hl"""An ${"implicit class"} may not be top-level""" @@ -369,7 +370,7 @@ object messages { } case class ImplicitCaseClass(cdef: untpd.TypeDef)(implicit ctx: Context) - extends Message(11) { + extends Message(ImplicitCaseClassID) { val kind = "Syntax" val msg = hl"""A ${"case class"} may not be defined as ${"implicit"}""" @@ -382,7 +383,7 @@ object messages { } case class ObjectMayNotHaveSelfType(mdef: untpd.ModuleDef)(implicit ctx: Context) - extends Message(12) { + extends Message(ObjectMayNotHaveSelfTypeID) { val kind = "Syntax" val msg = hl"""${"object"}s must not have a self ${"type"}""" @@ -400,7 +401,7 @@ object messages { } case class TupleTooLong(ts: List[untpd.Tree])(implicit ctx: Context) - extends Message(13) { + extends Message(TupleTooLongID) { import Definitions.MaxTupleArity val kind = "Syntax" val msg = hl"""A ${"tuple"} cannot have more than ${MaxTupleArity} members""" @@ -416,7 +417,7 @@ object messages { } case class RepeatedModifier(modifier: String)(implicit ctx:Context) - extends Message(14) { + extends Message(RepeatedModifierID) { val kind = "Syntax" val msg = hl"""repeated modifier $modifier""" @@ -438,7 +439,7 @@ object messages { } case class InterpolatedStringError()(implicit ctx:Context) - extends Message(15) { + extends Message(InterpolatedStringErrorID) { val kind = "Syntax" val msg = "error in interpolated string: identifier or block expected" val explanation = { @@ -456,7 +457,7 @@ object messages { } case class UnboundPlaceholderParameter()(implicit ctx:Context) - extends Message(16) { + extends Message(UnboundPlaceholderParameterID) { val kind = "Syntax" val msg = "unbound placeholder parameter; incorrect use of `_`" val explanation = @@ -489,7 +490,7 @@ object messages { } case class IllegalStartSimpleExpr(illegalToken: String)(implicit ctx: Context) - extends Message(17) { + extends Message(IllegalStartSimpleExprID) { val kind = "Syntax" val msg = "illegal start of simple expression" val explanation = { @@ -507,7 +508,8 @@ object messages { } } - case class MissingReturnType()(implicit ctx:Context) extends Message(18) { + case class MissingReturnType()(implicit ctx:Context) + extends Message(MissingReturnTypeID) { val kind = "Syntax" val msg = "missing return type" val explanation = @@ -519,7 +521,7 @@ object messages { } case class YieldOrDoExpectedInForComprehension()(implicit ctx: Context) - extends Message(19) { + extends Message(YieldOrDoExpectedInForComprehensionID) { val kind = "Syntax" val msg = hl"${"yield"} or ${"do"} expected" @@ -552,7 +554,7 @@ object messages { } case class ProperDefinitionNotFound()(implicit ctx: Context) - extends Message(20) { + extends Message(ProperDefinitionNotFoundID) { val kind = "Definition Not Found" val msg = hl"""Proper definition was not found in ${"@usecase"}""" @@ -591,7 +593,7 @@ object messages { } case class ByNameParameterNotSupported()(implicit ctx: Context) - extends Message(21) { + extends Message(ByNameParameterNotSupportedID) { val kind = "Syntax" val msg = "By-name parameter type not allowed here." @@ -615,7 +617,7 @@ object messages { } case class WrongNumberOfTypeArgs(fntpe: Type, expectedArgs: List[TypeParamInfo], actual: List[untpd.Tree])(implicit ctx: Context) - extends Message(22) { + extends Message(WrongNumberOfTypeArgsID) { val kind = "Syntax" private val expectedCount = expectedArgs.length @@ -661,7 +663,7 @@ object messages { } case class IllegalVariableInPatternAlternative()(implicit ctx: Context) - extends Message(23) { + extends Message(IllegalVariableInPatternAlternativeID) { val kind = "Syntax" val msg = "Variables are not allowed in alternative patterns" val explanation = { @@ -690,7 +692,7 @@ object messages { } case class TypeParamsTypeExpected(mods: untpd.Modifiers, identifier: TermName)(implicit ctx: Context) - extends Message(24) { + extends Message(TypeParamsTypeExpectedID) { val kind = "Syntax" val msg = hl"""Expected ${"type"} keyword for type parameter $identifier""" val explanation = @@ -703,7 +705,7 @@ object messages { } case class IdentifierExpected(identifier: String)(implicit ctx: Context) - extends Message(25) { + extends Message(IdentifierExpectedID) { val kind = "Syntax" val msg = "identifier expected" val explanation = { @@ -724,7 +726,7 @@ object messages { } case class AuxConstructorNeedsNonImplicitParameter()(implicit ctx:Context) - extends Message(26) { + extends Message(AuxConstructorNeedsNonImplicitParameterID) { val kind = "Syntax" val msg = "auxiliary constructor needs non-implicit parameter list" val explanation = @@ -739,7 +741,8 @@ object messages { |""" } - case class IncorrectRepeatedParameterSyntax()(implicit ctx: Context) extends Message(27) { + case class IncorrectRepeatedParameterSyntax()(implicit ctx: Context) + extends Message(IncorrectRepeatedParameterSyntaxID) { val kind = "Syntax" val msg = "'*' expected" val explanation = @@ -765,7 +768,8 @@ object messages { |""".stripMargin } - case class IllegalLiteral()(implicit ctx: Context) extends Message(28) { + case class IllegalLiteral()(implicit ctx: Context) + extends Message(IllegalLiteralID) { val kind = "Syntax" val msg = "illegal literal" val explanation = @@ -780,7 +784,7 @@ object messages { } case class PatternMatchExhaustivity(uncovered: String)(implicit ctx: Context) - extends Message(29) { + extends Message(PatternMatchExhaustivityID) { val kind = "Pattern Match Exhaustivity" val msg = hl"""|match may not be exhaustive. @@ -792,14 +796,14 @@ object messages { } case class MatchCaseUnreachable()(implicit ctx: Context) - extends Message(30) { + extends Message(MatchCaseUnreachableID) { val kind = s"""Match ${hl"case"} Unreachable""" val msg = "unreachable code" val explanation = "" } case class SeqWildcardPatternPos()(implicit ctx: Context) - extends Message(31) { + extends Message(SeqWildcardPatternPosID) { val kind = "Syntax" val msg = "`_*' can be used only for last argument" val explanation = { @@ -822,7 +826,8 @@ object messages { } } - case class IllegalStartOfSimplePattern()(implicit ctx: Context) extends Message(32) { + case class IllegalStartOfSimplePattern()(implicit ctx: Context) + extends Message(IllegalStartOfSimplePatternID) { val kind = "Syntax" val msg = "illegal start of simple pattern" val explanation = { @@ -902,13 +907,14 @@ object messages { } case class PkgDuplicateSymbol(existing: Symbol)(implicit ctx: Context) - extends Message(33) { + extends Message(PkgDuplicateSymbolID) { val kind = "Duplicate Symbol" val msg = hl"trying to define package with same name as `$existing`" val explanation = "" } - case class ExistentialTypesNoLongerSupported()(implicit ctx: Context) extends Message(34) { + case class ExistentialTypesNoLongerSupported()(implicit ctx: Context) + extends Message(ExistentialTypesNoLongerSupportedID) { val kind = "Syntax" val msg = hl"""|Existential types are no longer supported - @@ -930,7 +936,8 @@ object messages { |""" } - case class UnboundWildcardType()(implicit ctx: Context) extends Message(35) { + case class UnboundWildcardType()(implicit ctx: Context) + extends Message(UnboundWildcardTypeID) { val kind = "Syntax" val msg = "Unbound wildcard type" val explanation = @@ -974,7 +981,7 @@ object messages { |""" } - case class DanglingThisInPath()(implicit ctx: Context) extends Message(36) { + case class DanglingThisInPath()(implicit ctx: Context) extends Message(DanglingThisInPathID) { val kind = "Syntax" val msg = hl"""Expected an additional member selection after the keyword ${"this"}""" @@ -1011,7 +1018,7 @@ object messages { } case class OverridesNothing(member: Symbol)(implicit ctx: Context) - extends Message(37) { + extends Message(OverridesNothingID) { val kind = "Reference" val msg = hl"""${member} overrides nothing""" @@ -1023,7 +1030,7 @@ object messages { } case class OverridesNothingButNameExists(member: Symbol, existing: List[Denotations.SingleDenotation])(implicit ctx: Context) - extends Message(38) { + extends Message(OverridesNothingButNameExistsID) { val kind = "Reference" val msg = hl"""${member} has a different signature than the overridden declaration""" @@ -1042,7 +1049,7 @@ object messages { } case class ForwardReferenceExtendsOverDefinition(value: Symbol, definition: Symbol)(implicit ctx: Context) - extends Message(39) { + extends Message(ForwardReferenceExtendsOverDefinitionID) { val kind = "Reference" val msg = hl"`${definition.name}` is a forward reference extending over the definition of `${value.name}`" @@ -1061,7 +1068,7 @@ object messages { } case class ExpectedTokenButFound(expected: Token, found: Token, foundName: TermName)(implicit ctx: Context) - extends Message(40) { + extends Message(ExpectedTokenButFoundID) { val kind = "Syntax" private val expectedText = diff --git a/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala b/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala index bf727d51a701..858660075bb2 100644 --- a/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala +++ b/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala @@ -4,10 +4,8 @@ package reporting import org.junit.Assert._ import org.junit.Test - import core.Contexts._ - -import diagnostic.{ Message, MessageContainer, ExtendMessage } +import diagnostic.{ErrorMessageID, ExtendMessage, Message, MessageContainer} class TestMessageLaziness extends DottyTest { ctx = ctx.fresh.setReporter(new NonchalantReporter) @@ -19,7 +17,7 @@ class TestMessageLaziness extends DottyTest { override def report(m: MessageContainer)(implicit ctx: Context) = () } - case class LazyError() extends Message(1000) { + case class LazyError() extends Message(ErrorMessageID.LazyErrorId) { throw new Error("Didn't stay lazy.") val kind = "Test" From c5c1198b5121a6718c243fe24572c466f0559e7b Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Thu, 16 Feb 2017 14:57:44 +0100 Subject: [PATCH 06/14] Bootstrapped dotty should not depend on non-bootstrapped dotty-library --- project/Build.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/project/Build.scala b/project/Build.scala index 730632b747d6..2d4ac65d4a2b 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -105,7 +105,12 @@ object DottyBuild extends Build { (dottyOrganization % "dotty-sbt-bridge" % scalaVersion.value % "component").sources(), // sbt gets very unhappy if two projects use the same target - target := baseDirectory.value / ".." / "out" / name.value + target := baseDirectory.value / ".." / "out" / name.value, + + // The non-bootstrapped dotty-library is not necessary when bootstrapping dotty + autoScalaLibrary := false, + // ...but scala-library is + libraryDependencies += "org.scala-lang" % "scala-library" % scalacVersion ) /** Projects -------------------------------------------------------------- */ From 1f72283dcad2aab3753154f12f8b4a9d6cd9de36 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 17 Feb 2017 16:38:06 +0100 Subject: [PATCH 07/14] Fix #1991: Use classtag where available in unapply --- .../dotty/tools/dotc/typer/Applications.scala | 2 +- .../src/dotty/tools/dotc/typer/Typer.scala | 33 +++++++++++-------- tests/run/i1991.scala | 20 +++++++++++ 3 files changed, 41 insertions(+), 14 deletions(-) create mode 100644 tests/run/i1991.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 42c24ffb7723..0ed6ed6b49b6 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -916,7 +916,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => val result = assignType(cpy.UnApply(tree)(unapplyFn, unapplyImplicits, unapplyPatterns), ownType) unapp.println(s"unapply patterns = $unapplyPatterns") if ((ownType eq selType) || ownType.isError) result - else Typed(result, TypeTree(ownType)) + else tryWithClassTag(Typed(result, TypeTree(ownType)), selType) case tp => val unapplyErr = if (tp.isError) unapplyFn else notAnExtractor(unapplyFn) val typedArgsErr = args mapconserve (typed(_, defn.AnyType)) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 2b57cf778596..820044b8eafa 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -523,18 +523,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def handlePattern: Tree = { val tpt1 = typedTpt // special case for an abstract type that comes with a class tag - tpt1.tpe.dealias match { - case tref: TypeRef if !tref.symbol.isClass && !ctx.isAfterTyper => - inferImplicit(defn.ClassTagType.appliedTo(tref), - EmptyTree, tpt1.pos)(ctx.retractMode(Mode.Pattern)) match { - case SearchSuccess(arg, _, _, _) => - return typed(untpd.Apply(untpd.TypedSplice(arg), tree.expr), pt) - case _ => - } - case _ => - if (!ctx.isAfterTyper) tpt1.tpe.<:<(pt)(ctx.addMode(Mode.GADTflexible)) - } - ascription(tpt1, isWildcard = true) + if (!ctx.isAfterTyper) tpt1.tpe.<:<(pt)(ctx.addMode(Mode.GADTflexible)) + tryWithClassTag(ascription(tpt1, isWildcard = true), pt) } cases( ifPat = handlePattern, @@ -543,6 +533,23 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } } + /** For a typed tree `e: T`, if `T` is an abstract type for which an implicit class tag `ctag` + * exists, rewrite to `ctag(e)`. + * @pre We are in pattern-matching mode (Mode.Pattern) + */ + def tryWithClassTag(tree: Typed, pt: Type)(implicit ctx: Context) = tree.tpt.tpe.dealias match { + case tref: TypeRef if !tref.symbol.isClass && !ctx.isAfterTyper => + require(ctx.mode.is(Mode.Pattern)) + inferImplicit(defn.ClassTagType.appliedTo(tref), + EmptyTree, tree.tpt.pos)(ctx.retractMode(Mode.Pattern)) match { + case SearchSuccess(clsTag, _, _, _) => + typed(untpd.Apply(untpd.TypedSplice(clsTag), untpd.TypedSplice(tree.expr)), pt) + case _ => + tree + } + case _ => tree + } + def typedNamedArg(tree: untpd.NamedArg, pt: Type)(implicit ctx: Context) = track("typedNamedArg") { val arg1 = typed(tree.arg, pt) assignType(cpy.NamedArg(tree)(tree.name, arg1), arg1) @@ -1123,7 +1130,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val body1 = typed(tree.body, pt1) typr.println(i"typed bind $tree pt = $pt1 bodytpe = ${body1.tpe}") body1 match { - case UnApply(fn, Nil, arg :: Nil) if tree.body.isInstanceOf[untpd.Typed] => + case UnApply(fn, Nil, arg :: Nil) if tree.body.isInstanceOf[untpd.Typed] && !body1.tpe.isError => // A typed pattern `x @ (_: T)` with an implicit `ctag: ClassTag[T]` // was rewritten to `x @ ctag(_)`. // Rewrite further to `ctag(x @ _)` diff --git a/tests/run/i1991.scala b/tests/run/i1991.scala new file mode 100644 index 000000000000..524a3f311981 --- /dev/null +++ b/tests/run/i1991.scala @@ -0,0 +1,20 @@ +import scala.reflect.ClassTag + +class A[Foo](implicit tag: ClassTag[Foo]) { + object ExtractFoo { + def unapply(foo: Foo): Boolean = true + } + + def isFoo(x: Any) = x match { + case ExtractFoo() => true + //case foo: Foo => true + case _ => false + } +} + +object Test { + def main(args: Array[String]): Unit = { + assert((new A[String]).isFoo("foo")) // OK + assert(!(new A[String]).isFoo(42)) // OK in scalac, fails in Dotty + } +} From 2d2795e5151bea2cb012b3000c1bcc3621bd4468 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 17 Feb 2017 17:33:19 +0100 Subject: [PATCH 08/14] Fix binding of x @ (e: T) in ClassTag-based patmat We cannot assume that the untyped rhs of the bind is a `Typed` tree, with extractors it might be an `Apply` node, and in general it might also be a `Parens` node. --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 12 +++++------- tests/run/i1991.scala | 9 +++++++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 820044b8eafa..498fd001bdf8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1128,15 +1128,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedBind(tree: untpd.Bind, pt: Type)(implicit ctx: Context): Tree = track("typedBind") { val pt1 = fullyDefinedType(pt, "pattern variable", tree.pos) val body1 = typed(tree.body, pt1) - typr.println(i"typed bind $tree pt = $pt1 bodytpe = ${body1.tpe}") body1 match { - case UnApply(fn, Nil, arg :: Nil) if tree.body.isInstanceOf[untpd.Typed] && !body1.tpe.isError => - // A typed pattern `x @ (_: T)` with an implicit `ctag: ClassTag[T]` - // was rewritten to `x @ ctag(_)`. - // Rewrite further to `ctag(x @ _)` - assert(fn.symbol.owner == defn.ClassTagClass) + case UnApply(fn, Nil, arg :: Nil) if fn.symbol.owner == defn.ClassTagClass && !body1.tpe.isError => + // A typed pattern `x @ (e: T)` with an implicit `ctag: ClassTag[T]` + // was rewritten to `x @ ctag(e)` by `tryWithClassTag`. + // Rewrite further to `ctag(x @ e)` tpd.cpy.UnApply(body1)(fn, Nil, - typed(untpd.Bind(tree.name, arg).withPos(tree.pos), arg.tpe) :: Nil) + typed(untpd.Bind(tree.name, untpd.TypedSplice(arg)).withPos(tree.pos), arg.tpe) :: Nil) case _ => val sym = newPatternBoundSym(tree.name, body1.tpe, tree.pos) assignType(cpy.Bind(tree)(tree.name, body1), sym) diff --git a/tests/run/i1991.scala b/tests/run/i1991.scala index 524a3f311981..cec1dec89f75 100644 --- a/tests/run/i1991.scala +++ b/tests/run/i1991.scala @@ -10,6 +10,15 @@ class A[Foo](implicit tag: ClassTag[Foo]) { //case foo: Foo => true case _ => false } + + def testBind(x: Any) = x match { + case foo0: Foo => + (foo0: Foo) + case foo1 @ (_: Foo) => + (foo1: Foo) + case foo2 @ ExtractFoo() => + (foo2: Foo) + } } object Test { From e1dcd1a1b20cbab0ba97193a4925e61dec65df05 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 17 Feb 2017 18:23:06 +0100 Subject: [PATCH 09/14] checkNoPrivateLeaks: Use correct position for errors Previously we never used the `pos` argument of `checkNoPrivateLeaks` and instead used `sym.pos`, this makes a difference for calls to `avoidPrivateLeaks` coming from `TreeUnpickler` where we should use `tree.pos` instead. --- compiler/src/dotty/tools/dotc/typer/Checking.scala | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 27b0f28ca914..fb0497c2b9b1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -356,8 +356,7 @@ object Checking { */ def checkNoPrivateLeaks(sym: Symbol, pos: Position)(implicit ctx: Context): Type = { class NotPrivate extends TypeMap { - type Errors = List[(String, Position)] - var errors: Errors = Nil + var errors: List[String] = Nil def accessBoundary(sym: Symbol): Symbol = if (sym.is(Private) || !sym.owner.isClass) sym.owner @@ -383,8 +382,8 @@ object Checking { val prevErrors = errors var tp1 = if (isLeaked(tp.symbol)) { - errors = (em"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}", - sym.pos) :: errors + errors = + em"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}" :: errors tp } else mapOver(tp) @@ -408,7 +407,7 @@ object Checking { } val notPrivate = new NotPrivate val info = notPrivate(sym.info) - notPrivate.errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) } + notPrivate.errors.foreach(ctx.errorOrMigrationWarning(_, pos)) info } From f8a93f59a2c47330bb91422e5a1d254320f33aa7 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Thu, 16 Feb 2017 23:35:18 +0100 Subject: [PATCH 10/14] Disable tests that require scala-compiler This is necessary if we ever want to get rid of our dependency on scala-compiler --- compiler/test/dotc/tests.scala | 1 - tests/{ => disabled/scalac-dependent}/neg/selfreq.scala | 0 tests/{ => disabled/scalac-dependent}/pos-special/i859.scala | 0 tests/{ => disabled/scalac-dependent}/pos/t5604/ReplConfig.scala | 0 .../{ => disabled/scalac-dependent}/pos/t5604/ReplReporter.scala | 0 tests/{ => disabled/scalac-dependent}/pos/t5899.scala | 0 tests/{ => disabled/scalac-dependent}/pos/t7591.scala | 0 tests/{ => disabled/scalac-dependent}/pos/trait-force-info.scala | 0 tests/{ => disabled/scalac-dependent}/run/t1618.scala | 0 tests/{ => disabled/scalac-dependent}/run/t7775.scala | 0 10 files changed, 1 deletion(-) rename tests/{ => disabled/scalac-dependent}/neg/selfreq.scala (100%) rename tests/{ => disabled/scalac-dependent}/pos-special/i859.scala (100%) rename tests/{ => disabled/scalac-dependent}/pos/t5604/ReplConfig.scala (100%) rename tests/{ => disabled/scalac-dependent}/pos/t5604/ReplReporter.scala (100%) rename tests/{ => disabled/scalac-dependent}/pos/t5899.scala (100%) rename tests/{ => disabled/scalac-dependent}/pos/t7591.scala (100%) rename tests/{ => disabled/scalac-dependent}/pos/trait-force-info.scala (100%) rename tests/{ => disabled/scalac-dependent}/run/t1618.scala (100%) rename tests/{ => disabled/scalac-dependent}/run/t7775.scala (100%) diff --git a/compiler/test/dotc/tests.scala b/compiler/test/dotc/tests.scala index 6ef6bb7413d0..52478c009f25 100644 --- a/compiler/test/dotc/tests.scala +++ b/compiler/test/dotc/tests.scala @@ -160,7 +160,6 @@ class tests extends CompilerTest { @Test def rewrites = compileFile(posScala2Dir, "rewrites", "-rewrite" :: scala2mode) - @Test def pos_859 = compileFile(posSpecialDir, "i859", scala2mode)(allowDeepSubtypes) @Test def pos_t8146a = compileFile(posSpecialDir, "t8146a")(allowDeepSubtypes) @Test def pos_t5545 = { diff --git a/tests/neg/selfreq.scala b/tests/disabled/scalac-dependent/neg/selfreq.scala similarity index 100% rename from tests/neg/selfreq.scala rename to tests/disabled/scalac-dependent/neg/selfreq.scala diff --git a/tests/pos-special/i859.scala b/tests/disabled/scalac-dependent/pos-special/i859.scala similarity index 100% rename from tests/pos-special/i859.scala rename to tests/disabled/scalac-dependent/pos-special/i859.scala diff --git a/tests/pos/t5604/ReplConfig.scala b/tests/disabled/scalac-dependent/pos/t5604/ReplConfig.scala similarity index 100% rename from tests/pos/t5604/ReplConfig.scala rename to tests/disabled/scalac-dependent/pos/t5604/ReplConfig.scala diff --git a/tests/pos/t5604/ReplReporter.scala b/tests/disabled/scalac-dependent/pos/t5604/ReplReporter.scala similarity index 100% rename from tests/pos/t5604/ReplReporter.scala rename to tests/disabled/scalac-dependent/pos/t5604/ReplReporter.scala diff --git a/tests/pos/t5899.scala b/tests/disabled/scalac-dependent/pos/t5899.scala similarity index 100% rename from tests/pos/t5899.scala rename to tests/disabled/scalac-dependent/pos/t5899.scala diff --git a/tests/pos/t7591.scala b/tests/disabled/scalac-dependent/pos/t7591.scala similarity index 100% rename from tests/pos/t7591.scala rename to tests/disabled/scalac-dependent/pos/t7591.scala diff --git a/tests/pos/trait-force-info.scala b/tests/disabled/scalac-dependent/pos/trait-force-info.scala similarity index 100% rename from tests/pos/trait-force-info.scala rename to tests/disabled/scalac-dependent/pos/trait-force-info.scala diff --git a/tests/run/t1618.scala b/tests/disabled/scalac-dependent/run/t1618.scala similarity index 100% rename from tests/run/t1618.scala rename to tests/disabled/scalac-dependent/run/t1618.scala diff --git a/tests/run/t7775.scala b/tests/disabled/scalac-dependent/run/t7775.scala similarity index 100% rename from tests/run/t7775.scala rename to tests/disabled/scalac-dependent/run/t7775.scala From 1df5ef72a99c67d37a69f983dc7485fab4728cc9 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Thu, 16 Feb 2017 13:07:27 +0100 Subject: [PATCH 11/14] Remove unused flags --- .../tools/dotc/config/CompilerCommand.scala | 14 +- .../tools/dotc/config/ScalaSettings.scala | 173 +----------------- .../xsbt/ScalaCompilerForUnitTesting.scala | 1 + 3 files changed, 15 insertions(+), 173 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/CompilerCommand.scala b/compiler/src/dotty/tools/dotc/config/CompilerCommand.scala index 19ede3cece9b..6e0c60555210 100644 --- a/compiler/src/dotty/tools/dotc/config/CompilerCommand.scala +++ b/compiler/src/dotty/tools/dotc/config/CompilerCommand.scala @@ -93,19 +93,15 @@ object CompilerCommand extends DotClass { def shouldStopWithInfo = { import settings._ - Set(help, Xhelp, Yhelp, showPlugins, showPhases) exists (_.value) + Set(help, Xhelp, Yhelp) exists (_.value) } def infoMessage: String = { import settings._ - if (help.value) usageMessage - else if (Xhelp.value) xusageMessage - else if (Yhelp.value) yusageMessage -// else if (showPlugins.value) global.pluginDescriptions -// else if (showPhases.value) global.phaseDescriptions + ( -// if (debug.value) "\n" + global.phaseFlagDescriptions else "" -// ) - else "" + if (help.value) usageMessage + else if (Xhelp.value) xusageMessage + else if (Yhelp.value) yusageMessage + else "" } if (summary.errors.nonEmpty) { diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index e4c90789cf0e..9aac7836c237 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -8,152 +8,76 @@ class ScalaSettings extends Settings.SettingGroup { protected def defaultClasspath = sys.env.getOrElse("CLASSPATH", ".") - /** Path related settings. - */ + /** Path related settings */ val bootclasspath = PathSetting("-bootclasspath", "Override location of bootstrap class files.", Defaults.scalaBootClassPath) val extdirs = PathSetting("-extdirs", "Override location of installed extensions.", Defaults.scalaExtDirs) val javabootclasspath = PathSetting("-javabootclasspath", "Override java boot classpath.", Defaults.javaBootClassPath) val javaextdirs = PathSetting("-javaextdirs", "Override java extdirs classpath.", Defaults.javaExtDirs) val sourcepath = PathSetting("-sourcepath", "Specify location(s) of source files.", "") // Defaults.scalaSourcePath - val argfiles = BooleanSetting("@", "A text file containing compiler arguments (options and source files)") val classpath = PathSetting("-classpath", "Specify where to find user class files.", defaultClasspath) withAbbreviation "-cp" val d = StringSetting("-d", "directory|jar", "destination for generated classfiles.", ".") val priorityclasspath = PathSetting("-priorityclasspath", "class path that takes precedence over all other paths (or testing only)", "") - /** Other settings. - */ - val dependencyfile = StringSetting("-dependencyfile", "file", "Set dependency tracking file.", ".scala_dependencies") + /** Other settings */ val deprecation = BooleanSetting("-deprecation", "Emit warning and location for usages of deprecated APIs.") val migration = BooleanSetting("-migration", "Emit warning and location for migration issues from Scala 2.") val encoding = StringSetting("-encoding", "encoding", "Specify character encoding used by source files.", Properties.sourceEncoding) val explaintypes = BooleanSetting("-explaintypes", "Explain type errors in more detail.") val explain = BooleanSetting("-explain", "Explain errors in more detail.") val feature = BooleanSetting("-feature", "Emit warning and location for usages of features that should be imported explicitly.") - val g = ChoiceSetting("-g", "level", "Set level of generated debugging info.", List("none", "source", "line", "vars", "notailcalls"), "vars") val help = BooleanSetting("-help", "Print a synopsis of standard options") + // FIXME: `-nowarn` is not used in the compiler, but sbt passes this as an option val nowarn = BooleanSetting("-nowarn", "Generate no warnings.") val color = ChoiceSetting("-color", "mode", "Colored output", List("always", "never"/*, "auto"*/), "always"/* "auto"*/) val target = ChoiceSetting("-target", "target", "Target platform for object files. All JVM 1.5 targets are deprecated.", - List("jvm-1.5", "jvm-1.5-fjbg", "jvm-1.5-asm", "jvm-1.6", "jvm-1.7", "jvm-1.8", "msil"), - "jvm-1.8") - val scalajs = BooleanSetting("-scalajs", "Compile in Scala.js mode (requires scalajs-library.jar on the classpath).") + List("jvm-1.5", "jvm-1.5-fjbg", "jvm-1.5-asm", "jvm-1.6", "jvm-1.7", "jvm-1.8", "msil"), "jvm-1.8") val unchecked = BooleanSetting("-unchecked", "Enable additional warnings where generated code depends on assumptions.") val uniqid = BooleanSetting("-uniqid", "Uniquely tag all identifiers in debugging output.") val usejavacp = BooleanSetting("-usejavacp", "Utilize the java.class.path in classpath resolution.") val verbose = BooleanSetting("-verbose", "Output messages about what the compiler is doing.") val version = BooleanSetting("-version", "Print product version and exit.") val pageWidth = IntSetting("-pagewidth", "Set page width", 80) - - val jvmargs = PrefixSetting("-J", "-J", "Pass directly to the runtime system.") - val defines = PrefixSetting("-Dproperty=value", "-D", "Pass -Dproperty=value directly to the runtime system.") - val toolcp = PathSetting("-toolcp", "Add to the runner classpath.", "") - val nobootcp = BooleanSetting("-nobootcp", "Do not use the boot classpath for the scala jars.") val strict = BooleanSetting("-strict", "Use strict type rules, which means some formerly legal code does not typecheck anymore.") - - val nospecialization = BooleanSetting("-no-specialization", "Ignore @specialize annotations.") val language = MultiStringSetting("-language", "feature", "Enable one or more language features.") val rewrite = OptionSetting[Rewrites]("-rewrite", "When used in conjunction with -language:Scala2 rewrites sources to migrate to new syntax") /** -X "Advanced" settings */ val Xhelp = BooleanSetting("-X", "Print a synopsis of advanced options.") - val assemname = StringSetting("-Xassem-name", "file", "(Requires -target:msil) Name of the output assembly.", "").dependsOn(target, "msil") - val assemrefs = StringSetting("-Xassem-path", "path", "(Requires -target:msil) List of assemblies referenced by the program.", ".").dependsOn(target, "msil") - val assemextdirs = StringSetting("-Xassem-extdirs", "dirs", "(Requires -target:msil) List of directories containing assemblies. default:lib", Defaults.scalaLibDir.path).dependsOn(target, "msil") - val sourcedir = StringSetting("-Xsourcedir", "directory", "(Requires -target:msil) Mirror source folder structure in output directory.", ".").dependsOn(target, "msil") - val checkInit = BooleanSetting("-Xcheckinit", "Wrap field accessors to throw an exception on uninitialized access.") - val noassertions = BooleanSetting("-Xdisable-assertions", "Generate no assertions or assumptions.") -// val elidebelow = IntSetting("-Xelide-below", "Calls to @elidable methods are omitted if method priority is lower than argument", -// elidable.MINIMUM, None, elidable.byName get _) val noForwarders = BooleanSetting("-Xno-forwarders", "Do not generate static forwarders in mirror classes.") - val genPhaseGraph = StringSetting("-Xgenerate-phase-graph", "file", "Generate the phase graphs (outputs .dot files) to fileX.dot.", "") - val XlogImplicits = BooleanSetting("-Xlog-implicits", "Show more detail on why some implicits are not applicable.") val XminImplicitSearchDepth = IntSetting("-Xmin-implicit-search-depth", "Set number of levels of implicit searches undertaken before checking for divergence.", 5) val xmaxInlines = IntSetting("-Xmax-inlines", "Maximal number of successive inlines", 32) - val logImplicitConv = BooleanSetting("-Xlog-implicit-conversions", "Print a message whenever an implicit conversion is inserted.") - val logReflectiveCalls = BooleanSetting("-Xlog-reflective-calls", "Print a message when a reflective method call is generated") - val logFreeTerms = BooleanSetting("-Xlog-free-terms", "Print a message when reification creates a free term.") - val logFreeTypes = BooleanSetting("-Xlog-free-types", "Print a message when reification resorts to generating a free type.") val maxClassfileName = IntSetting("-Xmax-classfile-name", "Maximum filename length for generated classes", 255, 72 to 255) val Xmigration = VersionSetting("-Xmigration", "Warn about constructs whose behavior may have changed since version.") - val Xsource = VersionSetting("-Xsource", "Treat compiler input as Scala source for the specified version.") - val Xverify = BooleanSetting("-Xverify", "Verify generic signatures in generated bytecode (asm backend only.)") - val plugin = MultiStringSetting("-Xplugin", "file", "Load one or more plugins from files.") - val disable = MultiStringSetting("-Xplugin-disable", "plugin", "Disable the given plugin(s).") - val showPlugins = BooleanSetting("-Xplugin-list", "Print a synopsis of loaded plugins.") - val require = MultiStringSetting("-Xplugin-require", "plugin", "Abort unless the given plugin(s) are available.") - val pluginsDir = StringSetting("-Xpluginsdir", "path", "Path to search compiler plugins.", Defaults.scalaPluginPath) val Xprint = PhasesSetting("-Xprint", "Print out program after") - val writeICode = PhasesSetting("-Xprint-icode", "Log internal icode to *.icode files after", "icode") - val Xprintpos = BooleanSetting("-Xprint-pos", "Print tree positions, as offsets.") val printtypes = BooleanSetting("-Xprint-types", "Print tree types (debugging option).") val XprintDiff = BooleanSetting("-Xprint-diff", "Print changed parts of the tree since last print.") val XprintDiffDel = BooleanSetting("-Xprint-diff-del", "Print chaged parts of the tree since last print including deleted parts.") val prompt = BooleanSetting("-Xprompt", "Display a prompt after each error (debugging option).") - val script = StringSetting("-Xscript", "object", "Treat the source file as a script and wrap it in a main method.", "") val mainClass = StringSetting("-Xmain-class", "path", "Class for manifest's Main-Class entry (only useful with -d )", "") - val Xshowcls = StringSetting("-Xshow-class", "class", "Show internal representation of class.", "") - val Xshowobj = StringSetting("-Xshow-object", "object", "Show internal representation of object.", "") - val showPhases = BooleanSetting("-Xshow-phases", "Print a synopsis of compiler phases.") - val sourceReader = StringSetting("-Xsource-reader", "classname", "Specify a custom method for reading source files.", "") val XnoValueClasses = BooleanSetting("-Xno-value-classes", "Do not use value classes. Helps debugging.") val XreplLineWidth = IntSetting("-Xrepl-line-width", "Maximial number of columns per line for REPL output", 390) - val XoldPatmat = BooleanSetting("-Xoldpatmat", "Use the pre-2.10 pattern matcher. Otherwise, the 'virtualizing' pattern matcher is used in 2.10.") - val XnoPatmatAnalysis = BooleanSetting("-Xno-patmat-analysis", "Don't perform exhaustivity/unreachability analysis. Also, ignore @switch annotation.") - val XfullLubs = BooleanSetting("-Xfull-lubs", "Retains pre 2.10 behavior of less aggressive truncation of least upper bounds.") - val wikiSyntax = BooleanSetting("-Xwiki-syntax", "Retains the Scala2 behavior of using Wiki Syntax in Scaladoc") - /** -Y "Private" settings - */ - val overrideObjects = BooleanSetting("-Yoverride-objects", "Allow member objects to be overridden.") + /** -Y "Private" settings */ val overrideVars = BooleanSetting("-Yoverride-vars", "Allow vars to be overridden.") val Yhelp = BooleanSetting("-Y", "Print a synopsis of private options.") - val browse = PhasesSetting("-Ybrowse", "Browse the abstract syntax tree after") val Ycheck = PhasesSetting("-Ycheck", "Check the tree at the end of") val YcheckMods = BooleanSetting("-Ycheck-mods", "Check that symbols and their defining trees have modifiers in sync") - val YcheckTypedTrees = BooleanSetting("-YcheckTypedTrees", "Check all constructured typed trees for type correctness") - val Yshow = PhasesSetting("-Yshow", "(Requires -Xshow-class or -Xshow-object) Show after") - val Ycloselim = BooleanSetting("-Yclosure-elim", "Perform closure elimination.") - val Ycompacttrees = BooleanSetting("-Ycompact-trees", "Use compact tree printer when displaying trees.") - val noCompletion = BooleanSetting("-Yno-completion", "Disable tab-completion in the REPL.") - val Ydce = BooleanSetting("-Ydead-code", "Perform dead code elimination.") val debug = BooleanSetting("-Ydebug", "Increase the quantity of debugging output.") val debugNames = BooleanSetting("-YdebugNames", "Show name-space indicators when printing names") val debugTrace = BooleanSetting("-Ydebug-trace", "Trace core operations") val debugFlags = BooleanSetting("-Ydebug-flags", "Print all flags of definitions") val debugOwners = BooleanSetting("-Ydebug-owners", "Print all owners of definitions (requires -Yprint-syms)") - //val doc = BooleanSetting ("-Ydoc", "Generate documentation") val termConflict = ChoiceSetting("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error") - val inlineHandlers = BooleanSetting("-Yinline-handlers", "Perform exception handler inlining when possible.") - val YinlinerWarnings = BooleanSetting("-Yinline-warnings", "Emit inlining warnings. (Normally surpressed due to high volume)") - val Ylinearizer = ChoiceSetting("-Ylinearizer", "which", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo") val log = PhasesSetting("-Ylog", "Log operations during") val Ylogcp = BooleanSetting("-Ylog-classpath", "Output information about what classpath is being applied.") - val Ynogenericsig = BooleanSetting("-Yno-generic-signatures", "Suppress generation of generic signatures for Java.") val YnoImports = BooleanSetting("-Yno-imports", "Compile without importing scala.*, java.lang.*, or Predef.") val YnoPredef = BooleanSetting("-Yno-predef", "Compile without importing Predef.") - val noAdaptedArgs = BooleanSetting("-Yno-adapted-args", "Do not adapt an argument list (either by inserting () or creating a tuple) to match the receiver.") - val selfInAnnots = BooleanSetting("-Yself-in-annots", "Include a \"self\" identifier inside of annotations.") - val Yshowtrees = BooleanSetting("-Yshow-trees", "(Requires -Xprint:) Print detailed ASTs in formatted form.") - val YshowtreesCompact = BooleanSetting("-Yshow-trees-compact", "(Requires -Xprint:) Print detailed ASTs in compact form.") - val YshowtreesStringified = BooleanSetting("-Yshow-trees-stringified", "(Requires -Xprint:) Print stringifications along with detailed ASTs.") - val Yshowsyms = BooleanSetting("-Yshow-syms", "Print the AST symbol hierarchy after each phase.") - val Yshowsymkinds = BooleanSetting("-Yshow-symkinds", "Print abbreviated symbol kinds next to symbol names.") val Yskip = PhasesSetting("-Yskip", "Skip") - val Ygenjavap = StringSetting("-Ygen-javap", "dir", "Generate a parallel output directory of .javap files.", "") val Ydumpclasses = StringSetting("-Ydump-classes", "dir", "Dump the generated bytecode to .class files (useful for reflective compilation that utilizes in-memory classloaders).", "") - val Ynosqueeze = BooleanSetting("-Yno-squeeze", "Disable creation of compact code in matching.") val YstopAfter = PhasesSetting("-Ystop-after", "Stop after") withAbbreviation ("-stop") // backward compat val YstopBefore = PhasesSetting("-Ystop-before", "Stop before") // stop before erasure as long as we have not debugged it fully - val refinementMethodDispatch = ChoiceSetting("-Ystruct-dispatch", "policy", "structural method dispatch policy", List("no-cache", "mono-cache", "poly-cache", "invoke-dynamic"), "poly-cache") - val Yrangepos = BooleanSetting("-Yrangepos", "Use range positions for syntax trees.") - val Ybuilderdebug = ChoiceSetting("-Ybuilder-debug", "manager", "Compile using the specified build manager.", List("none", "refined", "simple"), "none") - val Yreifycopypaste = BooleanSetting("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.") - val Yreplsync = BooleanSetting("-Yrepl-sync", "Do not use asynchronous code for repl startup") val YmethodInfer = BooleanSetting("-Yinfer-argument-types", "Infer types for arguments of overriden methods.") - val etaExpandKeepsStar = BooleanSetting("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.") - val Yinvalidate = StringSetting("-Yinvalidate", "classpath-entry", "Invalidate classpath entry before run", "") - val noSelfCheck = BooleanSetting("-Yno-self-type-checks", "Suppress check for self-type conformance among inherited members.") val YtraceContextCreation = BooleanSetting("-Ytrace-context-creation", "Store stack trace of context creations.") val YshowSuppressedErrors = BooleanSetting("-Yshow-suppressed-errors", "Also show follow-on errors and warnings that are normally supressed.") val Yheartbeat = BooleanSetting("-Yheartbeat", "show heartbeat stack trace of compiler operations.") @@ -167,52 +91,17 @@ class ScalaSettings extends Settings.SettingGroup { val YforceSbtPhases = BooleanSetting("-Yforce-sbt-phases", "Run the phases used by sbt for incremental compilation (ExtractDependencies and ExtractAPI) even if the compiler is ran outside of sbt, for debugging.") val YdumpSbtInc = BooleanSetting("-Ydump-sbt-inc", "For every compiled foo.scala, output the API representation and dependencies used for sbt incremental compilation in foo.inc, implies -Yforce-sbt-phases.") val YcheckAllPatmat = BooleanSetting("-Ycheck-all-patmat", "Check exhaustivity and redundancy of all pattern matching (used for testing the algorithm)") - def stop = YstopAfter - /** Area-specific debug output. - */ - val Ybuildmanagerdebug = BooleanSetting("-Ybuild-manager-debug", "Generate debug information for the Refined Build Manager compiler.") - val Ycompletion = BooleanSetting("-Ycompletion-debug", "Trace all tab completion activity.") - val Ydocdebug = BooleanSetting("-Ydoc-debug", "Trace all scaladoc activity.") - val Yidedebug = BooleanSetting("-Yide-debug", "Generate, validate and output trees using the interactive compiler.") - val Yinferdebug = BooleanSetting("-Yinfer-debug", "Trace type inference and implicit search.") - val Yissuedebug = BooleanSetting("-Yissue-debug", "Print stack traces when a context issues an error.") - val YmacrodebugLite = BooleanSetting("-Ymacro-debug-lite", "Trace essential macro-related activities.") - val YmacrodebugVerbose = BooleanSetting("-Ymacro-debug-verbose", "Trace all macro-related activities: compilation, generation of synthetics, classloading, expansion, exceptions.") - val Ypmatdebug = BooleanSetting("-Ypmat-debug", "Trace all pattern matcher activity.") - val Yposdebug = BooleanSetting("-Ypos-debug", "Trace position validation.") - val Yreifydebug = BooleanSetting("-Yreify-debug", "Trace reification.") - val Yrepldebug = BooleanSetting("-Yrepl-debug", "Trace all repl activity.") - val Ytyperdebug = BooleanSetting("-Ytyper-debug", "Trace all type assignments.") - val Ypatmatdebug = BooleanSetting("-Ypatmat-debug", "Trace pattern matching translation.") + /** Area-specific debug output */ val Yexplainlowlevel = BooleanSetting("-Yexplain-lowlevel", "When explaining type errors, show types at a lower level.") val YnoDoubleBindings = BooleanSetting("-Yno-double-bindings", "Assert no namedtype is bound twice (should be enabled only if program is error-free).") val YshowVarBounds = BooleanSetting("-Yshow-var-bounds", "Print type variables with their bounds") val YnoInline = BooleanSetting("-Yno-inline", "Suppress inlining.") + /** Linker specific flags */ val optimise = BooleanSetting("-optimise", "Generates faster bytecode by applying optimisations to the program") withAbbreviation "-optimize" - /** IDE-specific settings - */ - val YpresentationVerbose = BooleanSetting("-Ypresentation-verbose", "Print information about presentation compiler tasks.") - val YpresentationDebug = BooleanSetting("-Ypresentation-debug", "Enable debugging output for the presentation compiler.") - val YpresentationStrict = BooleanSetting("-Ypresentation-strict", "Do not report type errors in sources with syntax errors.") - - val YpresentationLog = StringSetting("-Ypresentation-log", "file", "Log presentation compiler events into file", "") - val YpresentationReplay = StringSetting("-Ypresentation-replay", "file", "Replay presentation compiler events from file", "") - val YpresentationDelay = IntSetting("-Ypresentation-delay", "Wait number of ms after typing before starting typechecking", 0, 0 to 999) - - /** Doc specific settings */ - val template = OptionSetting[String]( - "-template", - "A mustache template for rendering each top-level entity in the API" - ) - - val resources = OptionSetting[String]( - "-resources", - "A directory containing static resources needed for the API documentation" - ) - + /** Dottydoc specific settings */ val siteRoot = StringSetting( "-siteroot", "site root", @@ -227,49 +116,5 @@ class ScalaSettings extends Settings.SettingGroup { sys.props("user.dir").split(sys.props("file.separator")).last ) - val DocVersion = StringSetting ( - "-Ydoc-version", - "version", - "An optional version number, to be appended to the title", - "" - ) - - val DocOutput = StringSetting ( - "-Ydoc-output", - "outdir", - "The output directory in which to place the documentation", - "." - ) - - val DocFooter = StringSetting ( - "-Ydoc-footer", - "footer", - "A footer on every Scaladoc page, by default the EPFL/Lightbend copyright notice. Can be overridden with a custom footer.", - "" - ) - - val DocUncompilable = StringSetting ( - "-Ydoc-no-compile", - "path", - "A directory containing sources which should be parsed, no more (e.g. AnyRef.scala)", - "" - ) - - //def DocUncompilableFiles(implicit ctx: Context) = DocUncompilable.value match { - // case "" => Nil - // case path => io.Directory(path).deepFiles.filter(_ hasExtension "scala").toList - //} - - val DocExternalDoc = MultiStringSetting ( - "-Ydoc-external-doc", - "external-doc", - "comma-separated list of classpath_entry_path#doc_URL pairs describing external dependencies." - ) - - val DocAuthor = BooleanSetting("-Ydoc-author", "Include authors.", true) - - val DocGroups = BooleanSetting ( - "-Ydoc:groups", - "Group similar functions together (based on the @group annotation)" - ) + val wikiSyntax = BooleanSetting("-Xwiki-syntax", "Retains the Scala2 behavior of using Wiki Syntax in Scaladoc") } diff --git a/sbt-bridge/test/xsbt/ScalaCompilerForUnitTesting.scala b/sbt-bridge/test/xsbt/ScalaCompilerForUnitTesting.scala index db037effeb70..40972902312c 100644 --- a/sbt-bridge/test/xsbt/ScalaCompilerForUnitTesting.scala +++ b/sbt-bridge/test/xsbt/ScalaCompilerForUnitTesting.scala @@ -22,6 +22,7 @@ import ScalaCompilerForUnitTesting.ExtractedSourceDependencies * source code using Scala compiler. */ class ScalaCompilerForUnitTesting(nameHashing: Boolean = false) { + import scala.language.reflectiveCalls /** * Compiles given source code using Scala compiler and returns API representation From de284145708df9014e30989310ff4cd4e711b697 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Thu, 16 Feb 2017 13:07:34 +0100 Subject: [PATCH 12/14] Add option to clear sbt log when using `~` --- project/Build.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/project/Build.scala b/project/Build.scala index 2d4ac65d4a2b..f03111f7617e 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -131,6 +131,8 @@ object DottyBuild extends Build { dependsOn(`dotty-compiler`). dependsOn(`dotty-library`). settings( + triggeredMessage in ThisBuild := Watched.clearWhenTriggered, + addCommandAlias("run", "dotty-compiler/run") ++ addCommandAlias( "partest", From ac2e14cf23572fdc51f535909cc8fda7778a1a93 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Mon, 20 Feb 2017 11:46:35 +0100 Subject: [PATCH 13/14] Make non-existent compiler options emit warnings instead of failing --- .../tools/dotc/config/CompilerCommand.scala | 3 +++ .../tools/dotc/config/PathResolver.scala | 2 +- .../tools/dotc/config/ScalaSettings.scala | 2 -- .../dotty/tools/dotc/config/Settings.scala | 20 +++++++++++-------- compiler/test/dotc/tests.scala | 2 -- tests/neg/customArgs/cliError.scala | 2 -- 6 files changed, 16 insertions(+), 15 deletions(-) delete mode 100644 tests/neg/customArgs/cliError.scala diff --git a/compiler/src/dotty/tools/dotc/config/CompilerCommand.scala b/compiler/src/dotty/tools/dotc/config/CompilerCommand.scala index 6e0c60555210..c2301a3aa252 100644 --- a/compiler/src/dotty/tools/dotc/config/CompilerCommand.scala +++ b/compiler/src/dotty/tools/dotc/config/CompilerCommand.scala @@ -104,6 +104,9 @@ object CompilerCommand extends DotClass { else "" } + // Print all warnings encountered during arguments parsing + summary.warnings.foreach(ctx.warning(_)) + if (summary.errors.nonEmpty) { summary.errors foreach (ctx.error(_)) ctx.echo(" dotc -help gives more information") diff --git a/compiler/src/dotty/tools/dotc/config/PathResolver.scala b/compiler/src/dotty/tools/dotc/config/PathResolver.scala index 184b3718a486..159989e6f97c 100644 --- a/compiler/src/dotty/tools/dotc/config/PathResolver.scala +++ b/compiler/src/dotty/tools/dotc/config/PathResolver.scala @@ -144,7 +144,7 @@ object PathResolver { } else { implicit val ctx = (new ContextBase).initialCtx - val ArgsSummary(sstate, rest, errors) = + val ArgsSummary(sstate, rest, errors, warnings) = ctx.settings.processArguments(args.toList, true) errors.foreach(println) val pr = new PathResolver()(ctx.fresh.setSettings(sstate)) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 9aac7836c237..fd79fcaa696c 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -26,8 +26,6 @@ class ScalaSettings extends Settings.SettingGroup { val explain = BooleanSetting("-explain", "Explain errors in more detail.") val feature = BooleanSetting("-feature", "Emit warning and location for usages of features that should be imported explicitly.") val help = BooleanSetting("-help", "Print a synopsis of standard options") - // FIXME: `-nowarn` is not used in the compiler, but sbt passes this as an option - val nowarn = BooleanSetting("-nowarn", "Generate no warnings.") val color = ChoiceSetting("-color", "mode", "Colored output", List("always", "never"/*, "auto"*/), "always"/* "auto"*/) val target = ChoiceSetting("-target", "target", "Target platform for object files. All JVM 1.5 targets are deprecated.", List("jvm-1.5", "jvm-1.5-fjbg", "jvm-1.5-asm", "jvm-1.6", "jvm-1.7", "jvm-1.8", "msil"), "jvm-1.8") diff --git a/compiler/src/dotty/tools/dotc/config/Settings.scala b/compiler/src/dotty/tools/dotc/config/Settings.scala index cffa047fee16..58fa6d366db8 100644 --- a/compiler/src/dotty/tools/dotc/config/Settings.scala +++ b/compiler/src/dotty/tools/dotc/config/Settings.scala @@ -44,10 +44,14 @@ object Settings { case class ArgsSummary( sstate: SettingsState, arguments: List[String], - errors: List[String]) { + errors: List[String], + warnings: List[String]) { def fail(msg: String) = - ArgsSummary(sstate, arguments, errors :+ msg) + ArgsSummary(sstate, arguments.tail, errors :+ msg, warnings) + + def warn(msg: String) = + ArgsSummary(sstate, arguments.tail, errors, warnings :+ msg) } case class Setting[T: ClassTag] private[Settings] ( @@ -106,11 +110,11 @@ object Settings { } def tryToSet(state: ArgsSummary): ArgsSummary = { - val ArgsSummary(sstate, arg :: args, errors) = state + val ArgsSummary(sstate, arg :: args, errors, warnings) = state def update(value: Any, args: List[String]) = - ArgsSummary(updateIn(sstate, value), args, errors) + ArgsSummary(updateIn(sstate, value), args, errors, warnings) def fail(msg: String, args: List[String]) = - ArgsSummary(sstate, args, errors :+ msg) + ArgsSummary(sstate, args, errors :+ msg, warnings) def missingArg = fail(s"missing argument for option $name", args) def doSet(argRest: String) = ((implicitly[ClassTag[T]], args): @unchecked) match { @@ -206,7 +210,7 @@ object Settings { * to get their arguments. */ protected def processArguments(state: ArgsSummary, processAll: Boolean, skipped: List[String]): ArgsSummary = { - def stateWithArgs(args: List[String]) = ArgsSummary(state.sstate, args, state.errors) + def stateWithArgs(args: List[String]) = ArgsSummary(state.sstate, args, state.errors, state.warnings) state.arguments match { case Nil => checkDependencies(stateWithArgs(skipped)) @@ -219,7 +223,7 @@ object Settings { if (state1 ne state) processArguments(state1, processAll, skipped) else loop(settings1) case Nil => - state.fail(s"bad option: '$x'") + processArguments(state.warn(s"bad option '$x' was ignored"), processAll, skipped) } loop(allSettings.toList) case arg :: args => @@ -229,7 +233,7 @@ object Settings { } def processArguments(arguments: List[String], processAll: Boolean)(implicit ctx: Context): ArgsSummary = - processArguments(ArgsSummary(ctx.sstate, arguments, Nil), processAll, Nil) + processArguments(ArgsSummary(ctx.sstate, arguments, Nil, Nil), processAll, Nil) def publish[T](settingf: Int => Setting[T]): Setting[T] = { val setting = settingf(_allSettings.length) diff --git a/compiler/test/dotc/tests.scala b/compiler/test/dotc/tests.scala index 52478c009f25..7af9033640b0 100644 --- a/compiler/test/dotc/tests.scala +++ b/compiler/test/dotc/tests.scala @@ -179,8 +179,6 @@ class tests extends CompilerTest { val negCustomArgs = negDir + "customArgs/" - @Test def neg_cli_error = compileFile(negCustomArgs, "cliError", List("-thisOptionDoesNotExist")) - @Test def neg_typers() = compileFile(negCustomArgs, "typers")(allowDoubleBindings) @Test def neg_overrideClass = compileFile(negCustomArgs, "overrideClass", scala2mode) @Test def neg_autoTupling = compileFile(negCustomArgs, "autoTuplingTest", args = "-language:noAutoTupling" :: Nil) diff --git a/tests/neg/customArgs/cliError.scala b/tests/neg/customArgs/cliError.scala deleted file mode 100644 index b2f0f6cdc4af..000000000000 --- a/tests/neg/customArgs/cliError.scala +++ /dev/null @@ -1,2 +0,0 @@ -// nopos-error -object Test From d4febc68b5bf06b1f180e927aca319ae6221c758 Mon Sep 17 00:00:00 2001 From: Enno Runne Date: Mon, 20 Feb 2017 15:02:39 +0100 Subject: [PATCH 14/14] Use Message ID enum --- .../dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java | 3 ++- .../src/dotty/tools/dotc/reporting/diagnostic/messages.scala | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java index 43930a56e0f1..c74130b445cf 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java @@ -48,7 +48,8 @@ public enum ErrorMessageID { OverridesNothingID, OverridesNothingButNameExistsID, ForwardReferenceExtendsOverDefinitionID, - ExpectedTokenButFoundID; + ExpectedTokenButFoundID, + MixedLeftAndRightAssociativeOpsID; public int errorNumber() { return ordinal() - 2; diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index ed1c5642f331..7fccebef9427 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1094,7 +1094,7 @@ object messages { } case class MixedLeftAndRightAssociativeOps(op1: Name, op2: Name, op2LeftAssoc: Boolean)(implicit ctx: Context) - extends Message(41) { + extends Message(MixedLeftAndRightAssociativeOpsID) { val kind = "Syntax" val op1Asso = if (op2LeftAssoc) "which is right-associative" else "which is left-associative" val op2Asso = if (op2LeftAssoc) "which is left-associative" else "which is right-associative"