diff options
Diffstat (limited to 'src')
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 _ => |