Skip to content

Make more parts of stdlib compile #1826

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

Merged
merged 20 commits into from
Dec 21, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
8 changes: 8 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,14 @@ object Types {
case _ => false
}

/** Is this the type of a method with a leading empty parameter list?
*/
def isNullaryMethod(implicit ctx: Context): Boolean = this match {
case MethodType(Nil, _) => true
case tp: PolyType => tp.resultType.isNullaryMethod
case _ => false
}

/** Is this an alias TypeBounds? */
def isAlias: Boolean = this.isInstanceOf[TypeAlias]

Expand Down
26 changes: 14 additions & 12 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -657,18 +657,20 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
case err: ErrorType => untpd.cpy.Apply(tree)(fun1, tree.args).withType(err)
case TryDynamicCallType => typedDynamicApply(tree, pt)
case _ =>
tryEither {
implicit ctx => simpleApply(fun1, proto)
} {
(failedVal, failedState) =>
def fail = { failedState.commit(); failedVal }
// Try once with original prototype and once (if different) with tupled one.
// The reason we need to try both is that the decision whether to use tupled
// or not was already taken but might have to be revised when an implicit
// is inserted on the qualifier.
tryWithImplicitOnQualifier(fun1, originalProto).getOrElse(
if (proto eq originalProto) fail
else tryWithImplicitOnQualifier(fun1, proto).getOrElse(fail))
if (originalProto.isDropped) fun1
else
tryEither {
implicit ctx => simpleApply(fun1, proto)
} {
(failedVal, failedState) =>
def fail = { failedState.commit(); failedVal }
// Try once with original prototype and once (if different) with tupled one.
// The reason we need to try both is that the decision whether to use tupled
// or not was already taken but might have to be revised when an implicit
// is inserted on the qualifier.
tryWithImplicitOnQualifier(fun1, originalProto).getOrElse(
if (proto eq originalProto) fail
else tryWithImplicitOnQualifier(fun1, proto).getOrElse(fail))
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,22 @@ object ProtoTypes {
/** Somebody called the `tupled` method of this prototype */
def isTupled: Boolean = myTupled.isInstanceOf[FunProto]

/** If true, the application of this prototype was canceled. */
private var toDrop: Boolean = false

/** Cancel the application of this prototype. This can happen for a nullary
* application `f()` if `f` refers to a symbol that exists both in parameterless
* form `def f` and nullary method form `def f()`. A common example for such
* a method is `toString`. If in that case the type in the denotation is
* parameterless, we compensate by dropping the application.
*/
def markAsDropped() = {
assert(args.isEmpty)
toDrop = true
}

def isDropped: Boolean = toDrop

override def toString = s"FunProto(${args mkString ","} => $resultType)"

def map(tm: TypeMap)(implicit ctx: Context): FunProto =
Expand Down
23 changes: 18 additions & 5 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1640,13 +1640,19 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
case _ => false
}

/** Add apply node or implicit conversions. Two strategies are tried, and the first
* that is successful is picked. If neither of the strategies are successful, continues with
* `fallBack`.
/** Potentially add apply node or implicit conversions. Before trying either,
* if the function is applied to an empty parameter list (), we try
*
* 0th strategy: If `tree` overrides a nullary method, mark the prototype
* so that the argument is dropped and return `tree` itself.
*
* After that, two strategies are tried, and the firs that is successful is picked.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: firs -> first

* If neither of the strategies are successful, continues with`fallBack`.
*
* 1st strategy: Try to insert `.apply` so that the result conforms to prototype `pt`.
* This strategy is not tried if the prototype represents already
* another `.apply` or `.apply()` selection.
*
* 2nd strategy: If tree is a select `qual.name`, try to insert an implicit conversion
* around the qualifier part `qual` so that the result conforms to the expected type
* with wildcard result type.
Expand All @@ -1661,8 +1667,15 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def tryImplicit =
tryInsertImplicitOnQualifier(tree, pt).getOrElse(fallBack)

if (isApplyProto(pt)) tryImplicit
else tryEither(tryApply(_))((_, _) => tryImplicit)
pt match {
case pt @ FunProto(Nil, _, _)
if tree.symbol.allOverriddenSymbols.exists(_.info.isNullaryMethod) =>
pt.markAsDropped()
tree
case _ =>
if (isApplyProto(pt)) tryImplicit
else tryEither(tryApply(_))((_, _) => tryImplicit)
}
}

/** If this tree is a select node `qual.name`, try to insert an implicit conversion
Expand Down
5 changes: 0 additions & 5 deletions compiler/test/dotc/scala-collections.blacklist
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@
# | ^^^^
# | cyclic reference involving method toString

../scala-scala/src/library/scala/collection/mutable/ImmutableMapAdaptor.scala
# 78 | override def toString() = imap.toString()
# | ^^^^^^^^^^^^^^^
# | missing argument for parameter index of method apply: (index: Int)Char

../scala-scala/src/library/scala/collection/mutable/LinkedHashMap.scala
# 102 | protected class FilteredKeys(p: A => Boolean) extends super.FilteredKeys(p) {
# | ^^^^^^^^^^^^^^^^^^^^
Expand Down