Skip to content

Change 'mixed left- and right-associative operators' to Message #1985

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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) =>
Expand Down Expand Up @@ -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) =>
Expand Down
5 changes: 1 addition & 4 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
17 changes: 8 additions & 9 deletions compiler/src/dotty/tools/dotc/config/CompilerCommand.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,21 +93,20 @@ 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 ""
}

// 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")
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/config/PathResolver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
173 changes: 8 additions & 165 deletions compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Large diffs are not rendered by default.

20 changes: 12 additions & 8 deletions compiler/src/dotty/tools/dotc/config/Settings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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] (
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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))
Expand All @@ -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 =>
Expand All @@ -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)
Expand Down
90 changes: 62 additions & 28 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand All @@ -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)

Expand Down Expand Up @@ -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 ------------------------------------------

Expand Down Expand Up @@ -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.
*/
Expand All @@ -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
}
Expand Down
45 changes: 38 additions & 7 deletions compiler/src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Names._, StdNames._, Contexts._, Symbols._, Flags._
import Decorators.StringDecorator
import util.{Chars, NameTransformer}
import Chars.isOperatorPart
import Definitions._

object NameOps {

Expand Down Expand Up @@ -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 */
Expand Down
11 changes: 5 additions & 6 deletions compiler/src/dotty/tools/dotc/core/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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) =>
Expand Down Expand Up @@ -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
Expand All @@ -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) =>
Expand Down Expand Up @@ -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) =>
Expand Down
Loading