aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/ast/CheckTrees.scala1
-rw-r--r--src/dotty/tools/dotc/config/Printers.scala2
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala2
-rw-r--r--src/dotty/tools/dotc/core/TyperState.scala54
-rw-r--r--src/dotty/tools/dotc/core/Types.scala21
-rw-r--r--src/dotty/tools/dotc/printing/PlainPrinter.scala7
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala23
-rw-r--r--src/dotty/tools/dotc/reporting/ConsoleReporter.scala15
-rw-r--r--src/dotty/tools/dotc/reporting/Reporter.scala166
-rw-r--r--src/dotty/tools/dotc/reporting/StoreReporter.scala15
-rw-r--r--src/dotty/tools/dotc/reporting/ThrowingReporter.scala6
-rw-r--r--src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala10
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala46
-rw-r--r--src/dotty/tools/dotc/typer/ErrorReporting.scala6
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala14
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala12
-rw-r--r--src/dotty/tools/dotc/typer/ProtoTypes.scala54
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala12
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala100
21 files changed, 347 insertions, 225 deletions
diff --git a/src/dotty/tools/dotc/ast/CheckTrees.scala b/src/dotty/tools/dotc/ast/CheckTrees.scala
index 832544706..254f002c1 100644
--- a/src/dotty/tools/dotc/ast/CheckTrees.scala
+++ b/src/dotty/tools/dotc/ast/CheckTrees.scala
@@ -34,6 +34,7 @@ object CheckTrees {
tp namedPartsWith (tp => isLocal(tp.symbol))
def typeLeaks(tp: Type): Boolean = leakingTypes(tp).nonEmpty
def classLeaks(sym: ClassSymbol): Boolean =
+ (ctx.owner is Method) || // can't hoist classes out of method bodies
(sym.info.parents exists typeLeaks) ||
(sym.decls.toList exists (t => typeLeaks(t.info)))
leakingTypes(block.tpe)
diff --git a/src/dotty/tools/dotc/config/Printers.scala b/src/dotty/tools/dotc/config/Printers.scala
index 680dee7ab..5bfe1d0b6 100644
--- a/src/dotty/tools/dotc/config/Printers.scala
+++ b/src/dotty/tools/dotc/config/Printers.scala
@@ -25,5 +25,5 @@ object Printers {
val hk = noPrinter
val incremental = noPrinter
val config = noPrinter
- val transforms = new Printer
+ val transforms = noPrinter
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index c7e7dc50d..498f912f9 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -418,7 +418,7 @@ object SymDenotations {
/** Is this symbol a class that does not extend `AnyVal`? */
final def isNonValueClass(implicit ctx: Context): Boolean =
- isClass && !derivesFrom(defn.AnyValClass)
+ isClass && !derivesFrom(defn.AnyValClass) && (symbol ne defn.NothingClass)
/** Is this symbol a class references to which that are supertypes of null? */
final def isNullableClass(implicit ctx: Context): Boolean =
diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala
index 59c934e0d..6a3ac4467 100644
--- a/src/dotty/tools/dotc/core/TyperState.scala
+++ b/src/dotty/tools/dotc/core/TyperState.scala
@@ -11,7 +11,10 @@ import printing.{Showable, Printer}
import printing.Texts._
import collection.mutable
-class TyperState(val reporter: Reporter) extends DotClass with Showable {
+class TyperState(r: Reporter) extends DotClass with Showable {
+
+ /** The current reporter */
+ def reporter = r
/** The current constraint set */
def constraint: Constraint = new Constraint(SimpleMap.Empty, SimpleMap.Empty)
@@ -56,11 +59,17 @@ class TyperState(val reporter: Reporter) extends DotClass with Showable {
/** Can this state be transitively committed until the top-level? */
def isGlobalCommittable: Boolean = false
+ def tryWithFallback[T](op: => T)(fallback: => T)(implicit ctx: Context): T = unsupported("tryWithFallBack")
+
override def toText(printer: Printer): Text = "ImmutableTyperState"
}
-class MutableTyperState(previous: TyperState, reporter: Reporter, override val isCommittable: Boolean)
-extends TyperState(reporter) {
+class MutableTyperState(previous: TyperState, r: Reporter, override val isCommittable: Boolean)
+extends TyperState(r) {
+
+ private var myReporter = r
+
+ override def reporter = myReporter
private var myConstraint: Constraint = previous.constraint
@@ -112,5 +121,44 @@ extends TyperState(reporter) {
constraint = constraint.remove(poly)
}
+ /** Try operation `op`; if it produces errors, execute `fallback` with constraint and
+ * reporter as they were before `op` was executed. This is similar to `typer/tryEither`,
+ * but with one important difference: Any type variable instantiations produced by `op`
+ * are persisted even if `op` fails. This is normally not what one wants and therefore
+ * it is recommended to use
+ *
+ * tryEither { implicit ctx => op } { (_, _) => fallBack }
+ *
+ * instead of
+ *
+ * ctx.tryWithFallback(op)(fallBack)
+ *
+ * `tryWithFallback` is only used when an implicit parameter search fails
+ * and the whole expression is subsequently retype-checked with a Wildcard
+ * expected type (so as to allow an implicit conversion on the result and
+ * avoid over-constraining the implicit parameter search). In this case,
+ * the only type variables that might be falsely instantiated by `op` but
+ * not by `fallBack` are type variables in the typed expression itself, and
+ * these will be thrown away and new ones will be created on re-typing.
+ * So `tryWithFallback` is safe. It is also necessary because without it
+ * we do not propagate enough instantiation information into the implicit search
+ * and this might lead to a missing parameter type error. This is exhibited
+ * at several places in the test suite (for instance in `pos_typers`).
+ * Overall, this is rather ugly, but despite trying for 2 days I have not
+ * found a better solution.
+ */
+ override def tryWithFallback[T](op: => T)(fallback: => T)(implicit ctx: Context): T = {
+ val savedReporter = myReporter
+ val savedConstraint = myConstraint
+ myReporter = new StoreReporter
+ val result = op
+ if (!reporter.hasErrors) result
+ else {
+ myReporter = savedReporter
+ myConstraint = savedConstraint
+ fallback
+ }
+ }
+
override def toText(printer: Printer): Text = constraint.toText(printer)
}
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 088a2e3af..89facfee5 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -756,6 +756,11 @@ object Types {
def typeParamNamed(name: TypeName)(implicit ctx: Context): Symbol =
classSymbol.decls.lookup(name) orElse member(name).symbol
+ /** If this is a prototype with some ignored component, reveal one more
+ * layer of it. Otherwise the type itself.
+ */
+ def deepenProto(implicit ctx: Context): Type = this
+
// ----- Substitutions -----------------------------------------------------
/** Substitute all types that refer in their symbol attribute to
@@ -1057,12 +1062,13 @@ object Types {
if (owner.isTerm) d else d.asSeenFrom(prefix)
}
- private def checkSymAssign(sym: Symbol) =
+ private def checkSymAssign(sym: Symbol)(implicit ctx: Context) =
assert(
(lastSymbol eq sym) ||
(lastSymbol eq null) ||
(lastSymbol.defRunId != sym.defRunId) ||
- (lastSymbol.defRunId == NoRunId),
+ (lastSymbol.defRunId == NoRunId) ||
+ (lastSymbol.infoOrCompleter == ErrorType),
s"data race? overwriting symbol of $this / ${this.getClass} / ${lastSymbol.id} / ${sym.id}")
protected def sig: Signature = Signature.NotAMethod
@@ -1996,12 +2002,23 @@ object Types {
// cached because baseType needs parents
private var parentsCache: List[TypeRef] = null
+ /** The parent type refs as seen from the given prefix */
override def parents(implicit ctx: Context): List[TypeRef] = {
if (parentsCache == null)
parentsCache = cls.classParents.mapConserve(rebase(_).asInstanceOf[TypeRef])
parentsCache
}
+ /** The parent types with all type arguments */
+ def instantiatedParents(implicit ctx: Context): List[Type] =
+ parents mapConserve { pref =>
+ ((pref: Type) /: pref.classSymbol.typeParams) { (parent, tparam) =>
+ val targSym = decls.lookup(tparam.name)
+ if (targSym.exists) RefinedType(parent, targSym.name, targSym.info)
+ else parent
+ }
+ }
+
def derivedClassInfo(prefix: Type)(implicit ctx: Context) =
if (prefix eq this.prefix) this
else ClassInfo(prefix, cls, classParents, decls, selfInfo)
diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala
index 308470885..3a322648a 100644
--- a/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -251,22 +251,21 @@ class PlainPrinter(_ctx: Context) extends Printer {
case sym: Symbol if !sym.isCompleted => "this: ? =>"
case _ => "this: " ~ atPrec(InfixPrec) { toText(tp.selfType) } ~ " =>"
}
- val parentsText = Text(cparents.map(p =>
- toTextLocal(reconstituteParent(cls, p))), " with ")
val trueDecls = otherDecls.filterNot(treatAsTypeArg)
val declsText =
if (trueDecls.isEmpty || !ctx.settings.debug.value) Text()
else dclsText(trueDecls)
- tparamsText ~ " extends " ~ parentsText ~ "{" ~ selfText ~ declsText ~
+ tparamsText ~ " extends " ~ toTextParents(tp.parents) ~ "{" ~ selfText ~ declsText ~
"} at " ~ preText
case _ =>
": " ~ toTextGlobal(tp)
}
}
+ protected def toTextParents(parents: List[Type]): Text = Text(parents.map(toTextLocal), " with ")
+
protected def treatAsTypeParam(sym: Symbol): Boolean = false
protected def treatAsTypeArg(sym: Symbol): Boolean = false
- protected def reconstituteParent(cls: ClassSymbol, parent: Type): Type = parent
/** String representation of symbol's kind. */
def kindString(sym: Symbol): String = {
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index dd8f04d92..d0a681f90 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -7,7 +7,7 @@ import Contexts.Context, Scopes.Scope, Denotations._, Annotations.Annotation
import StdNames.nme
import ast.{Trees, untpd}
import typer.Namer
-import typer.ProtoTypes.{SelectionProto, ViewProto, FunProto}
+import typer.ProtoTypes.{SelectionProto, ViewProto, FunProto, IgnoredProto}
import Trees._
import scala.annotation.switch
@@ -108,10 +108,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}
return (toTextLocal(tycon) ~ "[" ~ Text(args map argText, ", ") ~ "]").close
}
- case tp: SelectionProto =>
- return toText(RefinedType(WildcardType, tp.name, tp.memberProto))
- case tp: ViewProto =>
- return toText(tp.argType) ~ " ?=>? " ~ toText(tp.resultType)
case tp: TypeRef =>
if ((tp.symbol is TypeParam | TypeArgument) && !ctx.phase.erasedTypes) {
return tp.info match {
@@ -119,10 +115,20 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
case _ => nameString(tp.symbol)
}
}
+ else if (tp.symbol.isAnonymousClass)
+ return toText(tp.info)
case ExprType(result) =>
return "=> " ~ toText(result)
+ case tp: ClassInfo =>
+ return toTextParents(tp.instantiatedParents) ~ "{...}"
+ case tp: SelectionProto =>
+ return toText(RefinedType(WildcardType, tp.name, tp.memberProto))
+ case tp: ViewProto =>
+ return toText(tp.argType) ~ " ?=>? " ~ toText(tp.resultType)
case FunProto(args, resultType, _) =>
return "funproto(" ~ toTextGlobal(args, ", ") ~ "):" ~ toText(resultType)
+ case tp: IgnoredProto =>
+ return "?"
case _ =>
}
super.toText(tp)
@@ -435,13 +441,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
sym.isType && (sym is ProtectedLocal) &&
(sym.allOverriddenSymbols exists (_ is TypeParam))
- override protected def reconstituteParent(cls: ClassSymbol, parent: Type): Type =
- (parent /: parent.classSymbol.typeParams) { (parent, tparam) =>
- val targSym = cls.decls.lookup(tparam.name)
- if (targSym.exists) RefinedType(parent, targSym.name, targSym.info)
- else parent
- }
-
override def toText(sym: Symbol): Text = {
if (sym.name == nme.IMPORT) {
def importString(tree: untpd.Tree) = s"import ${tree.show}"
diff --git a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala
index 1bad29e23..6991cdbb6 100644
--- a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala
+++ b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala
@@ -40,11 +40,16 @@ class ConsoleReporter(
}
}
- override def doReport(d: Diagnostic)(implicit ctx: Context): Unit =
- if (d.severity != ERROR || count(d.severity.level) <= ErrorLimit && !d.isSuppressed) {
- printMessageAndPos(label(d.severity) + d.msg, d.pos)
- if (d.severity == ERROR && ctx.settings.prompt.value) displayPrompt()
- }
+ override def doReport(d: Diagnostic)(implicit ctx: Context): Unit = d match {
+ case d: Error =>
+ printMessageAndPos(s"error: ${d.msg}", d.pos)
+ if (ctx.settings.prompt.value) displayPrompt()
+ case d: ConditionalWarning if !d.enablingOption.value =>
+ case d: Warning =>
+ printMessageAndPos(s"warning: ${d.msg}", d.pos)
+ case _ =>
+ printMessageAndPos(d.msg, d.pos)
+ }
def displayPrompt(): Unit = {
writer.print("\na)bort, s)tack, r)esume: ")
diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala
index b0404c6b3..82b0a1158 100644
--- a/src/dotty/tools/dotc/reporting/Reporter.scala
+++ b/src/dotty/tools/dotc/reporting/Reporter.scala
@@ -14,10 +14,17 @@ import typer.ErrorReporting.DiagnosticString
object Reporter {
- class Diagnostic(msgFn: => String, val pos: SourcePosition, val severity: Severity) extends Exception {
+ private val ERROR = 2
+ private val WARNING = 1
+ private val INFO = 0
+
+ class Diagnostic(msgFn: => String, val pos: SourcePosition, val level: Int) extends Exception {
import DiagnosticString._
+
private var myMsg: String = null
private var myIsNonSensical: Boolean = false
+
+ /** The message to report */
def msg: String = {
if (myMsg == null) {
myMsg = msgFn
@@ -29,48 +36,32 @@ object Reporter {
}
myMsg
}
+
+ /** Report in current reporter */
+ def report(implicit ctx: Context) = ctx.reporter.report(this)
+
def isNonSensical = { msg; myIsNonSensical }
def isSuppressed(implicit ctx: Context): Boolean = !ctx.settings.YshowSuppressedErrors.value && isNonSensical
- override def toString = s"$severity at $pos: $msg"
- override def getMessage() = msg
-
- def promotedSeverity(implicit ctx: Context): Severity =
- if (isConditionalWarning(severity) && enablingOption(severity).value) WARNING
- else severity
- }
- def Diagnostic(msgFn: => String, pos: SourcePosition, severity: Severity) =
- new Diagnostic(msgFn, pos, severity)
-
- class Severity(val level: Int) extends AnyVal {
- override def toString = this match {
- case VerboseINFO => "VerboseINFO"
- case INFO => "INFO"
- case DeprecationWARNING => "DeprecationWARNING"
- case UncheckedWARNING => "UncheckedWARNING"
- case FeatureWARNING => "FeatureWARNING"
- case WARNING => "WARNING"
- case ERROR => "ERROR"
- }
+ override def toString = s"$getClass at $pos: $msg"
+ override def getMessage() = msg
}
- final val VerboseINFO = new Severity(0)
- final val INFO = new Severity(1)
- final val DeprecationWARNING = new Severity(2)
- final val UncheckedWARNING = new Severity(3)
- final val FeatureWARNING = new Severity(4)
- final val WARNING = new Severity(5)
- final val ERROR = new Severity(6)
-
- def isConditionalWarning(s: Severity) =
- DeprecationWARNING.level <= s.level && s.level <= FeatureWARNING.level
+ class Error(msgFn: => String, pos: SourcePosition) extends Diagnostic(msgFn, pos, ERROR)
+ class Warning(msgFn: => String, pos: SourcePosition) extends Diagnostic(msgFn, pos, WARNING)
+ class Info(msgFn: => String, pos: SourcePosition) extends Diagnostic(msgFn, pos, INFO)
- val conditionalWarnings = List(DeprecationWARNING, UncheckedWARNING, FeatureWARNING)
-
- private def enablingOption(warning: Severity)(implicit ctx: Context) = warning match {
- case DeprecationWARNING => ctx.settings.deprecation
- case UncheckedWARNING => ctx.settings.unchecked
- case FeatureWARNING => ctx.settings.feature
+ abstract class ConditionalWarning(msgFn: => String, pos: SourcePosition) extends Warning(msgFn, pos) {
+ def enablingOption(implicit ctx: Context): Setting[Boolean]
+ }
+ class FeatureWarning(msgFn: => String, pos: SourcePosition) extends ConditionalWarning(msgFn, pos) {
+ def enablingOption(implicit ctx: Context) = ctx.settings.feature
+ }
+ class UncheckedWarning(msgFn: => String, pos: SourcePosition) extends ConditionalWarning(msgFn, pos) {
+ def enablingOption(implicit ctx: Context) = ctx.settings.unchecked
+ }
+ class DeprecationWarning(msgFn: => String, pos: SourcePosition) extends ConditionalWarning(msgFn, pos) {
+ def enablingOption(implicit ctx: Context) = ctx.settings.deprecation
}
}
@@ -80,30 +71,30 @@ trait Reporting { this: Context =>
/** For sending messages that are printed only if -verbose is set */
def inform(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(Diagnostic(msg, pos, VerboseINFO))
+ if (this.settings.verbose.value) echo(msg, pos)
def echo(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(Diagnostic(msg, pos, INFO))
+ reporter.report(new Info(msg, pos))
def deprecationWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(Diagnostic(msg, pos, DeprecationWARNING))
+ reporter.report(new DeprecationWarning(msg, pos))
def uncheckedWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(Diagnostic(msg, pos, UncheckedWARNING))
+ reporter.report(new UncheckedWarning(msg, pos))
def featureWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(Diagnostic(msg, pos, FeatureWARNING))
+ reporter.report(new FeatureWarning(msg, pos))
def warning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(Diagnostic(msg, pos, WARNING))
+ reporter.report(new Warning(msg, pos))
def error(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = {
// println("*** ERROR: " + msg) // !!! DEBUG
- reporter.report(Diagnostic(msg, pos, ERROR))
+ reporter.report(new Error(msg, pos))
}
def incompleteInputError(msg: String, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit =
- reporter.incomplete(Diagnostic(msg, pos, ERROR))(ctx)
+ reporter.incomplete(new Error(msg, pos))(ctx)
/** Log msg if current phase or its precedessor is mentioned in
* settings.log.
@@ -209,71 +200,54 @@ abstract class Reporter {
finally incompleteHandler = saved
}
- protected def isHidden(d: Diagnostic)(implicit ctx: Context) = d.promotedSeverity match {
- case VerboseINFO => !ctx.settings.verbose.value
- case DeprecationWARNING | UncheckedWARNING | FeatureWARNING => true
- case _ => false
- }
+ var errorCount = 0
+ var warningCount = 0
+ def hasErrors = errorCount > 0
+ def hasWarnings = warningCount > 0
- val count = new Array[Int](ERROR.level + 1)
+ val unreportedWarnings = new mutable.HashMap[String, Int] {
+ override def default(key: String) = 0
+ }
- def report(d: Diagnostic)(implicit ctx: Context): Unit =
- if (!isHidden(d)) {
- doReport(d)
- if (!d.isSuppressed) count(d.promotedSeverity.level) += 1
+ def report(d: Diagnostic)(implicit ctx: Context): Unit = if (!isHidden(d)) {
+ doReport(d)
+ if (!d.isSuppressed) d match {
+ case d: ConditionalWarning if !d.enablingOption.value => unreportedWarnings(d.enablingOption.name) += 1
+ case d: Warning => warningCount += 1
+ case d: Error => errorCount += 1
+ case d: Info => // nothing to do here
+ // match error if d is something else
}
+ }
def incomplete(d: Diagnostic)(implicit ctx: Context): Unit =
incompleteHandler(d)(ctx)
- def hasErrors = count(ERROR.level) > 0
- def hasWarnings = count(WARNING.level) > 0
- def errorCounts: Any = count.clone
-
- def wasSilent[T](counts: Any): Boolean = {
- val prevCount = counts.asInstanceOf[Array[Int]]
- var i = 0
- while (i < count.length) {
- if (prevCount(i) != count(i)) return false
- i += 1
- }
- true
+ /** Print a summary */
+ def printSummary(implicit ctx: Context): Unit = {
+ if (warningCount > 0) ctx.echo(countString(warningCount, "warning") + " found")
+ if (errorCount > 0) ctx.echo(countString(errorCount, "error") + " found")
+ for ((settingName, count) <- unreportedWarnings)
+ ctx.echo(s"there were $count ${settingName.tail} warning(s); re-run with $settingName for details")
}
/** Returns a string meaning "n elements". */
- private def countElementsAsString(n: Int, elements: String): String =
- n match {
- case 0 => "no " + elements + "s"
- case 1 => "one " + elements
- case 2 => "two " + elements + "s"
- case 3 => "three " + elements + "s"
- case 4 => "four " + elements + "s"
- case _ => n + " " + elements + "s"
- }
-
- protected def label(severity: Severity): String = severity match {
- case ERROR => "error: "
- case WARNING => "warning: "
- case _ => ""
+ private def countString(n: Int, elements: String): String = n match {
+ case 0 => "no " + elements + "s"
+ case 1 => "one " + elements
+ case 2 => "two " + elements + "s"
+ case 3 => "three " + elements + "s"
+ case 4 => "four " + elements + "s"
+ case _ => n + " " + elements + "s"
}
- protected def countString(severity: Severity) = {
- assert(severity.level >= WARNING.level)
- countElementsAsString(count(severity.level), label(severity).dropRight(2))
- }
+ /** Should this diagnostic not be reported at all? */
+ def isHidden(d: Diagnostic)(implicit ctx: Context): Boolean = false
- def printSummary(implicit ctx: Context): Unit = {
- if (count(WARNING.level) > 0) ctx.echo(countString(WARNING) + " found")
- if ( count(ERROR.level) > 0) ctx.echo(countString(ERROR ) + " found")
- for (cwarning <- conditionalWarnings) {
- val unreported = count(cwarning.level)
- if (unreported > 0) {
- val what = enablingOption(cwarning).name.tail
- ctx.warning(s"there were $unreported $what warning(s); re-run with -$what for details")
- }
- }
- }
+ /** Does this reporter contain not yet reported errors or warnings? */
+ def hasPending: Boolean = false
+ /** Issue all error messages in this reporter to next outer one, or make sure they are written. */
def flush()(implicit ctx: Context): Unit = {}
}
diff --git a/src/dotty/tools/dotc/reporting/StoreReporter.scala b/src/dotty/tools/dotc/reporting/StoreReporter.scala
index 67b90eec0..2864c01f8 100644
--- a/src/dotty/tools/dotc/reporting/StoreReporter.scala
+++ b/src/dotty/tools/dotc/reporting/StoreReporter.scala
@@ -4,7 +4,7 @@ package reporting
import core.Contexts.Context
import collection.mutable
-import Reporter.Diagnostic
+import Reporter.{Diagnostic, Error, Warning}
import config.Printers._
/**
@@ -20,6 +20,17 @@ class StoreReporter extends Reporter {
infos += d
}
+ override def hasPending: Boolean = infos != null && {
+ infos exists {
+ case d: Error => true
+ case d: Warning => true
+ case _ => false
+ }
+ }
+
override def flush()(implicit ctx: Context) =
- if (infos != null) infos foreach ctx.reporter.report
+ if (infos != null) {
+ infos foreach ctx.reporter.report
+ infos = null
+ }
}
diff --git a/src/dotty/tools/dotc/reporting/ThrowingReporter.scala b/src/dotty/tools/dotc/reporting/ThrowingReporter.scala
index d44a08fb6..eb854d513 100644
--- a/src/dotty/tools/dotc/reporting/ThrowingReporter.scala
+++ b/src/dotty/tools/dotc/reporting/ThrowingReporter.scala
@@ -10,6 +10,8 @@ import Reporter._
* This class implements a Reporter that stores all messages
*/
class ThrowingReporter(reportInfo: Reporter) extends Reporter {
- protected def doReport(d: Diagnostic)(implicit ctx: Context): Unit =
- if (d.severity == ERROR) throw d else reportInfo.report(d)
+ protected def doReport(d: Diagnostic)(implicit ctx: Context): Unit = d match {
+ case _: Error => throw d
+ case _ => reportInfo.report(d)
+ }
}
diff --git a/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala b/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala
index 93e24b27f..c1f240a23 100644
--- a/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala
+++ b/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala
@@ -4,16 +4,16 @@ package reporting
import scala.collection.mutable
import util.{SourcePosition, SourceFile}
-import Reporter.{Severity, Diagnostic}
+import Reporter.Diagnostic
import core.Contexts.Context
/**
- * This trait implements `isHidden` do that multiple messages per position
+ * This trait implements `isHidden` so that multiple messages per position
* are suppressed, unless they are of increasing severity.
*/
trait UniqueMessagePositions extends Reporter {
- private val positions = new mutable.HashMap[(SourceFile, Int), Severity]
+ private val positions = new mutable.HashMap[(SourceFile, Int), Int]
/** Logs a position and returns true if it was already logged.
* @note Two positions are considered identical for logging if they have the same point.
@@ -22,8 +22,8 @@ trait UniqueMessagePositions extends Reporter {
super.isHidden(d) || {
d.pos.exists && {
positions get (ctx.source, d.pos.point) match {
- case Some(s) if s.level >= d.severity.level => true
- case _ => positions((ctx.source, d.pos.point)) = d.severity; false
+ case Some(level) if level >= d.level => true
+ case _ => positions((ctx.source, d.pos.point)) = d.level; false
}
}
}
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index e6d012d68..e56132057 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -349,7 +349,7 @@ object Erasure {
tpd.DefDef(bridge, { paramss: List[List[tpd.Tree]] =>
val rhs = paramss.foldLeft(sel)((fun, vparams) =>
fun.tpe.widen match {
- case MethodType(names, types) => Apply(fun, (vparams, types).zipped.map(adapt))
+ case MethodType(names, types) => Apply(fun, (vparams, types).zipped.map(adapt(_, _, untpd.EmptyTree)))
case a => error(s"can not resolve apply type $a")
})
@@ -357,7 +357,7 @@ object Erasure {
})
}
- override def adapt(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
+ override def adapt(tree: Tree, pt: Type, original: untpd.Tree)(implicit ctx: Context): Tree =
ctx.traceIndented(i"adapting ${tree.showSummary}: ${tree.tpe} to $pt", show = true) {
assert(ctx.phase == ctx.erasurePhase.next, ctx.phase)
if (tree.isEmpty) tree else adaptToType(tree, pt)
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 0f47336fc..a4c26080d 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -346,7 +346,7 @@ trait Applications extends Compatibility { self: Typer =>
init()
def addArg(arg: Tree, formal: Type): Unit =
- typedArgBuf += adaptInterpolated(arg, formal.widenExpr)
+ typedArgBuf += adaptInterpolated(arg, formal.widenExpr, EmptyTree)
def makeVarArg(n: Int, elemFormal: Type): Unit = {
val args = typedArgBuf.takeRight(n).toList
@@ -434,7 +434,7 @@ trait Applications extends Compatibility { self: Typer =>
def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
def realApply(implicit ctx: Context): Tree = track("realApply") {
- var proto = new FunProto(tree.args, pt, this)
+ var proto = new FunProto(tree.args, ignoreIfProto(pt), this)
val fun1 = typedExpr(tree.fun, proto)
// Warning: The following line is dirty and fragile. We record that auto-tupling was demanded as
@@ -453,30 +453,13 @@ trait Applications extends Compatibility { self: Typer =>
else new ApplyToUntyped(tree, fun1, funRef, proto, pt)
val result = app.result
ConstFold(result)
- } { (failedVal, failedState) => fun1 match {
- case Select(qual, name) =>
- // try with prototype `[].name(args)`, this might succeed by inserting an
- // implicit conversion around []. (an example is Int + BigInt).
- tryEither { implicit ctx =>
- val simpleFunProto = new FunProto(tree.args, WildcardType, this) // drop result type, because views are disabled
- val selProto = SelectionProto(name, simpleFunProto, NoViewsAllowed)
- val qual1 = adaptInterpolated(qual, selProto)
- if (qual eq qual1) ctx.error("no progress")
- if (ctx.reporter.hasErrors) qual1
- else
- typedApply(
- cpy.Apply(tree,
- cpy.Select(fun1, untpd.TypedSplice(qual1), name),
- proto.typedArgs map untpd.TypedSplice),
- pt)
- } { (_, _) =>
- failedState.commit()
- failedVal
- }
- case _ =>
- failedState.commit()
- failedVal
- }
+ } { (failedVal, failedState) =>
+ val fun2 = tryInsertImplicit(fun1, proto)
+ if (fun1 eq fun2) {
+ failedState.commit()
+ failedVal
+ } else typedApply(
+ cpy.Apply(tree, untpd.TypedSplice(fun2), proto.typedArgs map untpd.TypedSplice), pt)
}
case _ =>
fun1.tpe match {
@@ -771,7 +754,7 @@ trait Applications extends Compatibility { self: Typer =>
def isAsSpecific(alt1: TermRef, tp1: Type, alt2: TermRef, tp2: Type): Boolean = ctx.traceIndented(i"isAsSpecific $tp1 $tp2", overload) { tp1 match {
case tp1: PolyType =>
def bounds(tparamRefs: List[TypeRef]) = tp1.paramBounds map (_.substParams(tp1, tparamRefs))
- val tparams = ctx.newTypeParams(alt1.symbol.owner, tp1.paramNames, EmptyFlags, bounds)
+ val tparams = ctx.newTypeParams(alt1.symbol, tp1.paramNames, EmptyFlags, bounds)
isAsSpecific(alt1, tp1.instantiate(tparams map (_.typeRef)), alt2, tp2)
case tp1: MethodType =>
def repeatedToSingle(tp: Type) = if (tp.isRepeatedParam) tp.argTypesHi.head else tp
@@ -927,7 +910,14 @@ trait Applications extends Compatibility { self: Typer =>
alts filter (normalizedCompatible(_, pt))
}
if (isDetermined(candidates)) candidates
- else narrowMostSpecific(candidates)
+ else narrowMostSpecific(candidates) match {
+ case result @ (alt1 :: alt2 :: _) =>
+ val deepPt = pt.deepenProto
+ if (deepPt ne pt) resolveOverloaded(alts, deepPt, targs)
+ else result
+ case result =>
+ result
+ }
}
}
diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala
index 8f9b01fe6..0b016769b 100644
--- a/src/dotty/tools/dotc/typer/ErrorReporting.scala
+++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala
@@ -28,7 +28,11 @@ object ErrorReporting {
def errorMsg(msg: String, cx: Context): String =
if (cx.mode is Mode.InferringReturnType) {
cx.tree match {
- case tree: Trees.ValOrDefDef[_] =>
+ case tree: untpd.ValOrDefDef =>
+ // Dotty deviation: Was Trees.ValOrDefDef[_], but this gives ValOrDefDef[Nothing] instead of
+ // ValOrDefDel[Null]. Scala handles it, but it looks accidental because bounds propagation
+ // fails if the parameter is invariant or cotravariant.
+ // See test pending/pos/boundspropagation.scala
val treeSym = ctx.symOfContextTree(tree)
if (treeSym.exists && treeSym.name == cycleSym.name && treeSym.owner == cycleSym.owner) {
val result = if (cycleSym.isSourceMethod) " result" else ""
diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala
index a32f552ed..d2a94e287 100644
--- a/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/src/dotty/tools/dotc/typer/Implicits.scala
@@ -368,7 +368,10 @@ trait Implicits { self: Typer =>
return defn.isValueSubClass(from.symbol, to.symbol)
case _ =>
}
+ case from: ValueType =>
+ ;
case _ =>
+ return false
}
inferView(dummyTreeOfType(from), to)(ctx.fresh.setExploreTyperState).isInstanceOf[SearchSuccess]
}
@@ -410,12 +413,15 @@ trait Implicits { self: Typer =>
else new ImplicitSearch(pt, argument, pos)
val result = isearch.bestImplicit
result match {
- case success: SearchSuccess =>
- // println(s"committing to ${success.tstate.show}")
- success.tstate.commit()
+ case result: SearchSuccess =>
+ result.tstate.commit()
+ result
+ case result: AmbiguousImplicits =>
+ val deepPt = pt.deepenProto
+ if (deepPt ne pt) inferImplicit(deepPt, argument, pos) else result
case _ =>
+ result
}
- result
}
}
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index bd44ccac5..9e34d549a 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -58,7 +58,7 @@ trait Inferencing { this: Checking =>
}
private var toMaximize: Boolean = false
def apply(x: Boolean, tp: Type): Boolean = tp.dealias match {
- case _: WildcardType =>
+ case _: WildcardType | _: ProtoType =>
false
case tvar: TypeVar if !tvar.isInstantiated =>
if (force == ForceDegree.none) false
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index c3f1dcc81..e9195a072 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -404,8 +404,18 @@ class Namer { typer: Typer =>
}
}
- final override def complete(denot: SymDenotation)(implicit ctx: Context) =
+ final override def complete(denot: SymDenotation)(implicit ctx: Context) = {
+ if (completions != noPrinter && ctx.typerState != this.ctx.typerState) {
+ completions.println(completions.getClass.toString)
+ def levels(c: Context): Int =
+ if (c.typerState eq this.ctx.typerState) 0
+ else if (c.typerState == null) -1
+ else if (c.outer.typerState == c.typerState) levels(c.outer)
+ else levels(c.outer) + 1
+ completions.println(s"!!!completing ${denot.symbol.showLocated} in buried typerState, gap = ${levels(ctx)}")
+ }
completeInCreationContext(denot)
+ }
def completeInCreationContext(denot: SymDenotation): Unit =
denot.info = typeSig(denot.symbol)
diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala
index 4aba4fb59..a72e98418 100644
--- a/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -71,6 +71,23 @@ object ProtoTypes {
override def viewExists(tp: Type, pt: Type)(implicit ctx: Context): Boolean = false
}
+ /** A trait for prototypes that match all types */
+ trait MatchAlways extends ProtoType {
+ def isMatchedBy(tp1: Type)(implicit ctx: Context) = true
+ def map(tm: TypeMap)(implicit ctx: Context): ProtoType = this
+ def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T = x
+ }
+
+ /** A class marking ignored prototypes that can be reviealed by `deepenProto` */
+ case class IgnoredProto(proto: ProtoType) extends UncachedGroundType with MatchAlways {
+ override def deepenProto(implicit ctx: Context): Type = proto
+ }
+
+ def ignoreIfProto(tp: Type): Type = tp match {
+ case proto: ProtoType => IgnoredProto(proto)
+ case _ => tp
+ }
+
/** A prototype for expressions [] that are part of a selection operation:
*
* [ ].name: proto
@@ -107,6 +124,8 @@ object ProtoTypes {
def map(tm: TypeMap)(implicit ctx: Context) = derivedSelectionProto(name, tm(memberProto), compat)
def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context) = ta(x, memberProto)
+ override def deepenProto(implicit ctx: Context) = derivedSelectionProto(name, memberProto.deepenProto, compat)
+
override def computeHash = addDelta(doHash(name, memberProto), if (compat eq NoViewsAllowed) 1 else 0)
}
@@ -126,8 +145,7 @@ object ProtoTypes {
if (name.isConstructorName) WildcardType
else tp match {
case tp: UnapplyFunProto => new UnapplySelectionProto(name)
- case tp: ProtoType => SelectionProto(name, WildcardType, typer)
- case _ => SelectionProto(name, tp, typer)
+ case tp => SelectionProto(name, ignoreIfProto(tp), typer)
}
/** A prototype for expressions [] that are in some unspecified selection operation
@@ -183,12 +201,10 @@ object ProtoTypes {
def typedArg(arg: untpd.Tree, formal: Type)(implicit ctx: Context): Tree = {
var targ = myTypedArg(arg)
if (targ == null) {
- val counts = ctx.reporter.errorCounts
targ = typer.typedUnadapted(arg, formal)
- if (ctx.reporter.wasSilent(counts))
- myTypedArg = myTypedArg.updated(arg, targ)
+ if (!ctx.reporter.hasPending) myTypedArg = myTypedArg.updated(arg, targ)
}
- typer.adapt(targ, formal)
+ typer.adapt(targ, formal, arg)
}
private var myTupled: Type = NoType
@@ -210,14 +226,17 @@ object ProtoTypes {
def map(tm: TypeMap)(implicit ctx: Context): FunProto =
derivedFunProto(args, tm(resultType), typer)
- def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T = ta(x, resultType)
+ def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T =
+ ta(ta.foldOver(x, typedArgs.tpes), resultType)
+
+ override def deepenProto(implicit ctx: Context) = derivedFunProto(args, resultType.deepenProto, typer)
}
/** A prototype for implicitly inferred views:
*
* []: argType => resultType
*/
- abstract case class ViewProto(argType: Type, override val resultType: Type)(implicit ctx: Context)
+ abstract case class ViewProto(argType: Type, override val resultType: Type)
extends CachedGroundType with ApplyingProto {
def isMatchedBy(tp: Type)(implicit ctx: Context): Boolean =
ctx.typer.isApplicable(tp, argType :: Nil, resultType)
@@ -228,13 +247,13 @@ object ProtoTypes {
def map(tm: TypeMap)(implicit ctx: Context): ViewProto = derivedViewProto(tm(argType), tm(resultType))
- def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T = ta(ta(x, argType), resultType)
+ def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T =
+ ta(ta(x, argType), resultType)
- override def namedPartsWith(p: NamedType => Boolean)(implicit ctx: Context): collection.Set[NamedType] =
- AndType.unchecked(argType, resultType).namedPartsWith(p) // this is more efficient than oring two namedParts sets
+ override def deepenProto(implicit ctx: Context) = derivedViewProto(argType, resultType.deepenProto)
}
- class CachedViewProto(argType: Type, resultType: Type)(implicit ctx: Context) extends ViewProto(argType, resultType) {
+ class CachedViewProto(argType: Type, resultType: Type) extends ViewProto(argType, resultType) {
override def computeHash = doHash(argType, resultType)
}
@@ -268,17 +287,15 @@ object ProtoTypes {
def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T =
ta(ta.foldOver(x, targs), resultType)
+
+ override def deepenProto(implicit ctx: Context) = derivedPolyProto(targs, resultType.deepenProto)
}
/** A prototype for expressions [] that are known to be functions:
*
* [] _
*/
- object AnyFunctionProto extends UncachedGroundType with ProtoType {
- def isMatchedBy(tp: Type)(implicit ctx: Context) = true
- def map(tm: TypeMap)(implicit ctx: Context) = this
- def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context) = x
- }
+ object AnyFunctionProto extends UncachedGroundType with MatchAlways
/** Add all parameters in given polytype `pt` to the constraint's domain.
* If the constraint contains already some of these parameters in its domain,
@@ -356,7 +373,8 @@ object ProtoTypes {
case tp @ PolyParam(poly, pnum) =>
ctx.typerState.constraint.at(tp) match {
case bounds: TypeBounds => wildApprox(WildcardType(bounds))
- case _ => WildcardType(wildApprox(poly.paramBounds(pnum)).bounds)
+ case NoType => WildcardType(wildApprox(poly.paramBounds(pnum)).bounds)
+ case inst => wildApprox(inst)
}
case MethodParam(mt, pnum) =>
WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum))))
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 13f65d424..48c263085 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -52,10 +52,14 @@ trait TypeAssigner {
def apply(tp: Type) = tp match {
case tp: TermRef if toAvoid(tp) && variance > 0 =>
apply(tp.info)
- case tp: TypeRef if toAvoid(tp.prefix) =>
+ case tp: TypeRef if (forbidden contains tp.symbol) || toAvoid(tp.prefix) =>
tp.info match {
- case TypeAlias(ref) => apply(ref)
- case _ => mapOver(tp)
+ case TypeAlias(ref) =>
+ apply(ref)
+ case info: ClassInfo =>
+ mapOver(info.instantiatedParents.reduceLeft(AndType(_, _)))
+ case _ =>
+ mapOver(tp)
}
case tp: RefinedType =>
val tp1 @ RefinedType(parent1, _) = mapOver(tp)
@@ -247,7 +251,7 @@ trait TypeAssigner {
tree.withType(defn.UnitType)
def assignType(tree: untpd.Block, stats: List[Tree], expr: Tree)(implicit ctx: Context) =
- tree.withType(avoid(expr.tpe, localSyms(stats)))
+ tree.withType(avoid(expr.tpe, localSyms(stats) filter (_.isTerm)))
def assignType(tree: untpd.If, thenp: Tree, elsep: Tree)(implicit ctx: Context) =
tree.withType(thenp.tpe | elsep.tpe)
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index f4b52ce09..050fcbc76 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -70,6 +70,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
* (3) Change pattern Idents id (but not wildcards) to id @ _
*/
def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): Tree = track("typedIdent") {
+ val refctx = ctx
val name = tree.name
/** Method is necessary because error messages need to bind to
@@ -179,7 +180,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
if (imp.isWildcardImport) {
val pre = imp.site
if (!isDisabled(imp, pre) && !(imp.excluded contains name.toTermName)) {
- val denot = pre.member(name)
+ val denot = pre.member(name).accessibleFrom(pre)(refctx)
if (reallyExists(denot)) return pre.select(name, denot)
}
}
@@ -953,7 +954,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def typed(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = /*>|>*/ ctx.traceIndented (i"typing $tree", typr, show = true) /*<|<*/ {
if (!tree.isEmpty && ctx.typerState.isGlobalCommittable) assert(tree.pos.exists, i"position not set for $tree")
- try adapt(typedUnadapted(tree, pt), pt)
+ try adapt(typedUnadapted(tree, pt), pt, tree)
catch {
case ex: CyclicReference => errorTree(tree, cyclicErrorMsg(ex))
case ex: FatalTypeError => errorTree(tree, ex.getMessage)
@@ -1008,20 +1009,46 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
}
- def tryInsertApply(tree: Tree, pt: Type)(fallBack: (Tree, TyperState) => Tree)(implicit ctx: Context): Tree =
- tryEither {
- implicit ctx =>
- val sel = typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt)
- if (sel.tpe.isError) sel else adapt(sel, pt)
- } {
- fallBack
+ /** Try to insert `.apply` so that the result conforms to prototype `pt`.
+ * If that fails try to insert an implicit conversion around the qualifier
+ * part of `tree`. If either result conforms to `pt`, adapt it, else
+ * continue with `fallBack`.
+ */
+ def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: (Tree, TyperState) => Tree)(implicit ctx: Context): Tree =
+ tryEither { implicit ctx =>
+ val sel = typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt)
+ if (sel.tpe.isError) sel else adapt(sel, pt)
+ } { (failedTree, failedState) =>
+ val tree1 = tryInsertImplicit(tree, pt)
+ if (tree1 eq tree) fallBack(failedTree, failedState)
+ else adapt(tree1, pt)
}
- def adapt(tree: Tree, pt: Type)(implicit ctx: Context) = /*>|>*/ track("adapt") /*<|<*/ {
+ /** If this tree is a select node `qual.name`, try to insert an implicit conversion
+ * `c` around `qual` so that `c(qual).name` conforms to `pt`. If that fails
+ * return `tree` itself.
+ */
+ def tryInsertImplicit(tree: Tree, pt: ProtoType)(implicit ctx: Context): Tree = ctx.traceIndented(i"try ins impl $tree $pt") { tree match {
+ case Select(qual, name) =>
+ val normalizedProto = pt match {
+ case pt: FunProto => pt.derivedFunProto(pt.args, WildcardType, pt.typer) // drop result type, because views are disabled
+ case _ => pt
+ }
+ val qualProto = SelectionProto(name, normalizedProto, NoViewsAllowed)
+ tryEither { implicit ctx =>
+ val qual1 = adaptInterpolated(qual, qualProto, EmptyTree)
+ if ((qual eq qual1) || ctx.reporter.hasErrors) tree
+ else typedSelect(cpy.Select(tree, untpd.TypedSplice(qual1), name), pt)
+ } { (_, _) => tree
+ }
+ case _ => tree
+ }}
+
+ def adapt(tree: Tree, pt: Type, original: untpd.Tree = untpd.EmptyTree)(implicit ctx: Context) = /*>|>*/ track("adapt") /*<|<*/ {
/*>|>*/ ctx.traceIndented(i"adapting $tree of type ${tree.tpe} to $pt", typr, show = true) /*<|<*/ {
interpolateUndetVars(tree)
tree overwriteType tree.tpe.simplified
- adaptInterpolated(tree, pt)
+ adaptInterpolated(tree, pt, original)
}
}
@@ -1063,7 +1090,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
* (14) When in mode EXPRmode, apply a view
* If all this fails, error
*/
- def adaptInterpolated(tree: Tree, pt: Type)(implicit ctx: Context): Tree = {
+ def adaptInterpolated(tree: Tree, pt: Type, original: untpd.Tree)(implicit ctx: Context): Tree = {
assert(pt.exists)
@@ -1077,7 +1104,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def expectedStr = err.expectedTypeStr(pt)
resolveOverloaded(alts, pt) match {
case alt :: Nil =>
- adapt(tree.withType(alt), pt)
+ adapt(tree.withType(alt), pt, original)
case Nil =>
def noMatches =
errorTree(tree,
@@ -1086,7 +1113,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def hasEmptyParams(denot: SingleDenotation) = denot.info.paramTypess == ListOfNil
pt match {
case pt: FunProto =>
- tryInsertApply(tree, pt)((_, _) => noMatches)
+ tryInsertApplyOrImplicit(tree, pt)((_, _) => noMatches)
case _ =>
if (altDenots exists (_.info.paramTypess == ListOfNil))
typed(untpd.Apply(untpd.TypedSplice(tree), Nil), pt)
@@ -1112,7 +1139,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
adaptToArgs(wtp, pt.tupled)
else
tree
- case _ => tryInsertApply(tree, pt) {
+ case _ => tryInsertApplyOrImplicit(tree, pt) {
val more = tree match {
case Apply(_, _) => " more"
case _ => ""
@@ -1123,24 +1150,31 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def adaptNoArgs(wtp: Type): Tree = wtp match {
case wtp: ExprType =>
- adaptInterpolated(tree.withType(wtp.resultType), pt)
+ adaptInterpolated(tree.withType(wtp.resultType), pt, original)
case wtp: ImplicitMethodType if constrainResult(wtp, pt) =>
- def implicitArgError(msg: => String): Tree = {
- ctx.error(msg, tree.pos.endPos)
- EmptyTree
- }
- val args = (wtp.paramNames, wtp.paramTypes).zipped map { (pname, formal) =>
- def where = d"parameter $pname of $methodStr"
- inferImplicit(formal, EmptyTree, tree.pos.endPos) match {
- case SearchSuccess(arg, _, _) =>
- adapt(arg, formal)
- case ambi: AmbiguousImplicits =>
- implicitArgError(s"ambiguous implicits: ${ambi.explanation} of $where")
- case failure: SearchFailure =>
- implicitArgError(d"no implicit argument of type $formal found for $where" + failure.postscript)
+ def addImplicitArgs = {
+ def implicitArgError(msg: => String): Tree = {
+ ctx.error(msg, tree.pos.endPos)
+ EmptyTree
+ }
+ val args = (wtp.paramNames, wtp.paramTypes).zipped map { (pname, formal) =>
+ def where = d"parameter $pname of $methodStr"
+ inferImplicit(formal, EmptyTree, tree.pos.endPos) match {
+ case SearchSuccess(arg, _, _) =>
+ adapt(arg, formal)
+ case ambi: AmbiguousImplicits =>
+ implicitArgError(s"ambiguous implicits: ${ambi.explanation} of $where")
+ case failure: SearchFailure =>
+ implicitArgError(d"no implicit argument of type $formal found for $where" + failure.postscript)
+ }
}
+ adapt(tpd.Apply(tree, args), pt)
}
- adapt(tpd.Apply(tree, args), pt)
+ if ((pt eq WildcardType) || original.isEmpty) addImplicitArgs
+ else
+ ctx.typerState.tryWithFallback(addImplicitArgs) {
+ adapt(typed(original, WildcardType), pt, EmptyTree)
+ }
case wtp: MethodType if !pt.isInstanceOf[SingletonType] =>
val arity =
if (defn.isFunctionType(pt)) defn.functionArity(pt)
@@ -1149,7 +1183,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
if (arity >= 0 && !tree.symbol.isConstructor)
typed(etaExpand(tree, wtp, arity), pt)
else if (wtp.paramTypes.isEmpty)
- adaptInterpolated(tpd.Apply(tree, Nil), pt)
+ adaptInterpolated(tpd.Apply(tree, Nil), pt, EmptyTree)
else
errorTree(tree,
d"""missing arguments for $methodStr
@@ -1208,14 +1242,14 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
if (pt.isInstanceOf[PolyProto]) tree
else {
val (_, tvars) = constrained(poly, tree)
- adaptInterpolated(tree appliedToTypes tvars, pt)
+ adaptInterpolated(tree appliedToTypes tvars, pt, original)
}
case wtp =>
pt match {
case pt: FunProto =>
adaptToArgs(wtp, pt)
case pt: PolyProto =>
- tryInsertApply(tree, pt) {
+ tryInsertApplyOrImplicit(tree, pt) {
(_, _) => tree // error will be reported in typedTypeApply
}
case _ =>