diff options
Diffstat (limited to 'src/dotty/tools')
-rw-r--r-- | src/dotty/tools/dotc/config/Printers.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TyperState.scala | 54 | ||||
-rw-r--r-- | src/dotty/tools/dotc/reporting/StoreReporter.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Erasure.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 12 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/ProtoTypes.scala | 9 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 53 |
8 files changed, 105 insertions, 36 deletions
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/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/reporting/StoreReporter.scala b/src/dotty/tools/dotc/reporting/StoreReporter.scala index ea8199102..2864c01f8 100644 --- a/src/dotty/tools/dotc/reporting/StoreReporter.scala +++ b/src/dotty/tools/dotc/reporting/StoreReporter.scala @@ -29,5 +29,8 @@ class StoreReporter extends Reporter { } 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/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 92acb7939..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 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 1438f9e16..a72e98418 100644 --- a/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -204,7 +204,7 @@ object ProtoTypes { targ = typer.typedUnadapted(arg, formal) if (!ctx.reporter.hasPending) myTypedArg = myTypedArg.updated(arg, targ) } - typer.adapt(targ, formal) + typer.adapt(targ, formal, arg) } private var myTupled: Type = NoType @@ -236,7 +236,7 @@ object ProtoTypes { * * []: 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) @@ -253,7 +253,7 @@ object ProtoTypes { 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) } @@ -373,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/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 5d477193c..050fcbc76 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -954,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) @@ -1036,7 +1036,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } val qualProto = SelectionProto(name, normalizedProto, NoViewsAllowed) tryEither { implicit ctx => - val qual1 = adaptInterpolated(qual, qualProto) + 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 @@ -1044,11 +1044,11 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case _ => tree }} - def adapt(tree: Tree, pt: Type)(implicit ctx: Context) = /*>|>*/ track("adapt") /*<|<*/ { + 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) } } @@ -1090,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) @@ -1104,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, @@ -1150,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) @@ -1176,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 @@ -1235,7 +1242,7 @@ 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 { |