diff options
Diffstat (limited to 'compiler/src/dotty')
11 files changed, 112 insertions, 64 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/Positioned.scala b/compiler/src/dotty/tools/dotc/ast/Positioned.scala index bb6817603..51949c6fe 100644 --- a/compiler/src/dotty/tools/dotc/ast/Positioned.scala +++ b/compiler/src/dotty/tools/dotc/ast/Positioned.scala @@ -123,6 +123,8 @@ abstract class Positioned extends DotClass with Product { private def unionPos(pos: Position, xs: List[_]): Position = xs match { case (p: Positioned) :: xs1 => unionPos(pos union p.pos, xs1) + case (xs0: List[_]) :: xs1 => unionPos(unionPos(pos, xs0), xs1) + case _ :: xs1 => unionPos(pos, xs1) case _ => pos } diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 7ab8de39f..bf11a442e 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -3,7 +3,7 @@ package dotc package ast import core._ -import Types._, Names._, Flags._, util.Positions._, Contexts._, Constants._ +import Types._, Names._, NameOps._, Flags._, util.Positions._, Contexts._, Constants._ import SymDenotations._, Symbols._, Denotations._, StdNames._, Comments._ import annotation.tailrec import language.higherKinds @@ -316,7 +316,7 @@ object Trees { def namePos = if (pos.exists) if (rawMods.is(Synthetic)) Position(pos.point, pos.point) - else Position(pos.point, pos.point + name.length, pos.point) + else Position(pos.point, pos.point + name.stripModuleClassSuffix.length, pos.point) else pos } diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index 42df53fed..3aa20f15b 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -79,12 +79,12 @@ trait ConstraintHandling { if (Config.failOnInstantiationToNothing) assert(false, msg) else ctx.log(msg) } - constr.println(i"adding $description") + constr.println(i"adding $description in ${ctx.typerState.hashesStr}") val lower = constraint.lower(param) val res = addOneBound(param, bound, isUpper = true) && lower.forall(addOneBound(_, bound, isUpper = true)) - constr.println(i"added $description = $res") + constr.println(i"added $description = $res in ${ctx.typerState.hashesStr}") res } @@ -95,7 +95,7 @@ trait ConstraintHandling { val res = addOneBound(param, bound, isUpper = false) && upper.forall(addOneBound(_, bound, isUpper = false)) - constr.println(i"added $description = $res") + constr.println(i"added $description = $res in ${ctx.typerState.hashesStr}") res } @@ -108,12 +108,12 @@ trait ConstraintHandling { val up2 = p2 :: constraint.exclusiveUpper(p2, p1) val lo1 = constraint.nonParamBounds(p1).lo val hi2 = constraint.nonParamBounds(p2).hi - constr.println(i"adding $description down1 = $down1, up2 = $up2") + constr.println(i"adding $description down1 = $down1, up2 = $up2 ${ctx.typerState.hashesStr}") constraint = constraint.addLess(p1, p2) down1.forall(addOneBound(_, hi2, isUpper = true)) && up2.forall(addOneBound(_, lo1, isUpper = false)) } - constr.println(i"added $description = $res") + constr.println(i"added $description = $res ${ctx.typerState.hashesStr}") res } diff --git a/compiler/src/dotty/tools/dotc/core/TyperState.scala b/compiler/src/dotty/tools/dotc/core/TyperState.scala index 5c476c1cb..206438d86 100644 --- a/compiler/src/dotty/tools/dotc/core/TyperState.scala +++ b/compiler/src/dotty/tools/dotc/core/TyperState.scala @@ -79,6 +79,9 @@ class TyperState(r: Reporter) extends DotClass with Showable { def tryWithFallback[T](op: => T)(fallback: => T)(implicit ctx: Context): T = unsupported("tryWithFallBack") override def toText(printer: Printer): Text = "ImmutableTyperState" + + /** A string showing the hashes of all nested mutable typerstates */ + def hashesStr: String = "" } class MutableTyperState(previous: TyperState, r: Reporter, override val isCommittable: Boolean) @@ -207,4 +210,7 @@ extends TyperState(r) { } override def toText(printer: Printer): Text = constraint.toText(printer) + + override def hashesStr: String = hashCode.toString + " -> " + previous.hashesStr + } diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 5ed4fbdd7..3162f61b4 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1763,12 +1763,8 @@ object Parsers { TypeTree() // XX-METHOD-INFER } else { accept(COLON) - if (in.token == ARROW) { - if (owner.isTypeName && !(mods is Local)) - syntaxError(s"${if (mods is Mutable) "`var'" else "`val'"} parameters may not be call-by-name") - else if (imods.hasFlags) - syntaxError("implicit parameters may not be call-by-name") - } + if (in.token == ARROW && owner.isTypeName && !(mods is Local)) + syntaxError(s"${if (mods is Mutable) "`var'" else "`val'"} parameters may not be call-by-name") paramType() } val default = diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 61f23c214..ac25f7cfd 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -6,6 +6,7 @@ import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._, De import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annotation import StdNames.{nme, tpnme} import ast.Trees._, ast._ +import typer.Implicits._ import config.Config import java.lang.Integer.toOctalString import config.Config.summarizeDepth @@ -484,6 +485,23 @@ class PlainPrinter(_ctx: Context) extends Printer { } }.close // todo: override in refined printer + def toText(result: SearchResult): Text = result match { + case result: SearchSuccess => + "SearchSuccess: " ~ toText(result.ref) ~ " via " ~ toText(result.tree) + case result: NonMatchingImplicit => + "NoImplicitMatches" + case result: DivergingImplicit => + "Diverging Implicit" + case result: ShadowedImplicit => + "Shadowed Implicit" + case result: FailedImplicit => + "Failed Implicit" + case result: AmbiguousImplicits => + "Ambiguous Implicit: " ~ toText(result.alt1) ~ " and " ~ toText(result.alt2) + case _ => + "?Unknown Implicit Result?" + } + private var maxSummarized = Int.MaxValue def summarized[T](depth: Int)(op: => T): T = { diff --git a/compiler/src/dotty/tools/dotc/printing/Printer.scala b/compiler/src/dotty/tools/dotc/printing/Printer.scala index 14b63012e..506773a4b 100644 --- a/compiler/src/dotty/tools/dotc/printing/Printer.scala +++ b/compiler/src/dotty/tools/dotc/printing/Printer.scala @@ -5,6 +5,7 @@ import core._ import Texts._, ast.Trees._ import Types.Type, Symbols.Symbol, Contexts.Context, Scopes.Scope, Constants.Constant, Names.Name, Denotations._, Annotations.Annotation +import typer.Implicits.SearchResult /** The base class of all printers */ @@ -94,7 +95,10 @@ abstract class Printer { /** Textual representation of tree */ def toText[T >: Untyped](tree: Tree[T]): Text - /** Perform string or text-producing operation `op` so that only a + /** Textual representation of implicit search result */ + def toText(result: SearchResult): Text + + /** Perform string or text-producing operation `op` so that only a * summarized text with given recursion depth is shown */ def summarized[T](depth: Int)(op: => T): T diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 592e80048..d4e74cf7d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -6,7 +6,8 @@ import core._ import ast.{Trees, untpd, tpd, TreeInfo} import util.Positions._ import util.Stats.{track, record, monitored} -import printing.Showable +import printing.{Showable, Printer} +import printing.Texts._ import Contexts._ import Types._ import Flags._ @@ -68,9 +69,9 @@ object Implicits { case mt: MethodType => mt.isImplicit || mt.paramTypes.length != 1 || - !(argType relaxed_<:< wildApprox(mt.paramTypes.head)(ctx.fresh.setExploreTyperState)) + !(argType relaxed_<:< wildApprox(mt.paramTypes.head, null, Set.empty)(ctx.fresh.setExploreTyperState)) case rtp => - discardForView(wildApprox(rtp), argType) + discardForView(wildApprox(rtp, null, Set.empty), argType) } case tpw: TermRef => false // can't discard overloaded refs @@ -219,14 +220,16 @@ object Implicits { } /** The result of an implicit search */ - abstract class SearchResult + abstract class SearchResult extends Showable { + def toText(printer: Printer): Text = printer.toText(this) + } /** A successful search * @param ref The implicit reference that succeeded * @param tree The typed tree that needs to be inserted * @param ctx The context after the implicit search */ - case class SearchSuccess(tree: tpd.Tree, ref: TermRef, level: Int, tstate: TyperState) extends SearchResult { + case class SearchSuccess(tree: tpd.Tree, ref: TermRef, level: Int, tstate: TyperState) extends SearchResult with Showable { override def toString = s"SearchSuccess($tree, $ref, $level)" } @@ -256,7 +259,7 @@ object Implicits { } /** An ambiguous implicits failure */ - class AmbiguousImplicits(alt1: TermRef, alt2: TermRef, val pt: Type, val argument: tpd.Tree) extends ExplainedSearchFailure { + class AmbiguousImplicits(val alt1: TermRef, val alt2: TermRef, val pt: Type, val argument: tpd.Tree) extends ExplainedSearchFailure { def explanation(implicit ctx: Context): String = em"both ${err.refStr(alt1)} and ${err.refStr(alt2)} $qualify" override def postscript(implicit ctx: Context) = @@ -380,7 +383,9 @@ trait ImplicitRunInfo { self: RunInfo => EmptyTermRefSet // on the other hand, the refs of `tp` are now not accurate, so `tp` is marked incomplete. } else { seen += t - iscope(t).companionRefs + val is = iscope(t) + if (!implicitScopeCache.contains(t)) incomplete += tp + is.companionRefs } } @@ -436,10 +441,8 @@ trait ImplicitRunInfo { self: RunInfo => if (ctx.typerState.ephemeral) record("ephemeral cache miss: implicitScope") else if (canCache && - ((tp eq rootTp) || // first type traversed is always cached - !incomplete.contains(tp) && // other types are cached if they are not incomplete - result.companionRefs.forall( // and all their companion refs are cached - implicitScopeCache.contains))) + ((tp eq rootTp) || // first type traversed is always cached + !incomplete.contains(tp))) // other types are cached if they are not incomplete implicitScopeCache(tp) = result result } @@ -604,6 +607,7 @@ trait Implicits { self: Typer => result match { case result: SearchSuccess => result.tstate.commit() + implicits.println(i"committing ${result.tstate.constraint} yielding ${ctx.typerState.constraint} ${ctx.typerState.hashesStr}") result case result: AmbiguousImplicits => val deepPt = pt.deepenProto @@ -649,7 +653,7 @@ trait Implicits { self: Typer => } /** The expected type where parameters and uninstantiated typevars are replaced by wildcard types */ - val wildProto = implicitProto(pt, wildApprox(_)) + val wildProto = implicitProto(pt, wildApprox(_, null, Set.empty)) /** Search failures; overridden in ExplainedImplicitSearch */ protected def nonMatchingImplicit(ref: TermRef, trail: List[MessageContainer]): SearchFailure = NoImplicitMatches diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 772d9385b..3860ba225 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -972,7 +972,7 @@ class Namer { typer: Typer => ctx.defContext(sym).denotNamed(original) def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match { case params :: paramss1 => - if (idx < params.length) wildApprox(params(idx)) + if (idx < params.length) wildApprox(params(idx), null, Set.empty) else paramProto(paramss1, idx - params.length) case nil => WildcardType diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index eb46a131f..d666b563e 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -437,65 +437,82 @@ object ProtoTypes { /** Approximate occurrences of parameter types and uninstantiated typevars * by wildcard types. */ - final def wildApprox(tp: Type, theMap: WildApproxMap = null)(implicit ctx: Context): Type = tp match { + final def wildApprox(tp: Type, theMap: WildApproxMap, seen: Set[PolyParam])(implicit ctx: Context): Type = tp match { case tp: NamedType => // default case, inlined for speed if (tp.symbol.isStatic) tp - else tp.derivedSelect(wildApprox(tp.prefix, theMap)) + else tp.derivedSelect(wildApprox(tp.prefix, theMap, seen)) case tp: RefinedType => // default case, inlined for speed - tp.derivedRefinedType(wildApprox(tp.parent, theMap), tp.refinedName, wildApprox(tp.refinedInfo, theMap)) + tp.derivedRefinedType( + wildApprox(tp.parent, theMap, seen), + tp.refinedName, + wildApprox(tp.refinedInfo, theMap, seen)) case tp: TypeAlias => // default case, inlined for speed - tp.derivedTypeAlias(wildApprox(tp.alias, theMap)) + tp.derivedTypeAlias(wildApprox(tp.alias, theMap, seen)) case tp @ PolyParam(poly, pnum) => - def unconstrainedApprox = WildcardType(wildApprox(poly.paramBounds(pnum)).bounds) - if (ctx.mode.is(Mode.TypevarsMissContext)) - unconstrainedApprox - else - ctx.typerState.constraint.entry(tp) match { - case bounds: TypeBounds => wildApprox(WildcardType(bounds)) - case NoType => unconstrainedApprox - case inst => wildApprox(inst) - } + def wildApproxBounds(bounds: TypeBounds) = + if (bounds.lo.isInstanceOf[NamedType] && bounds.hi.isInstanceOf[NamedType]) + WildcardType(wildApprox(bounds, theMap, seen).bounds) + else if (seen.contains(tp)) WildcardType + else WildcardType(wildApprox(bounds, theMap, seen + tp).bounds) + def unconstrainedApprox = wildApproxBounds(poly.paramBounds(pnum)) + def approxPoly = + if (ctx.mode.is(Mode.TypevarsMissContext)) unconstrainedApprox + else + ctx.typerState.constraint.entry(tp) match { + case bounds: TypeBounds => wildApproxBounds(bounds) + case NoType => unconstrainedApprox + case inst => wildApprox(inst, theMap, seen) + } + approxPoly case MethodParam(mt, pnum) => - WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum)))) + WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum), theMap, seen))) case tp: TypeVar => - wildApprox(tp.underlying) + wildApprox(tp.underlying, theMap, seen) case tp @ HKApply(tycon, args) => - wildApprox(tycon) match { + wildApprox(tycon, theMap, seen) match { case _: WildcardType => WildcardType // this ensures we get a * type - case tycon1 => tp.derivedAppliedType(tycon1, args.mapConserve(wildApprox(_))) + case tycon1 => tp.derivedAppliedType(tycon1, args.mapConserve(wildApprox(_, theMap, seen))) } case tp: AndType => - val tp1a = wildApprox(tp.tp1) - val tp2a = wildApprox(tp.tp2) - def wildBounds(tp: Type) = - if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp) - if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType]) - WildcardType(wildBounds(tp1a) & wildBounds(tp2a)) - else - tp.derivedAndType(tp1a, tp2a) + def approxAnd = { + val tp1a = wildApprox(tp.tp1, theMap, seen) + val tp2a = wildApprox(tp.tp2, theMap, seen) + def wildBounds(tp: Type) = + if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp) + if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType]) + WildcardType(wildBounds(tp1a) & wildBounds(tp2a)) + else + tp.derivedAndType(tp1a, tp2a) + } + approxAnd case tp: OrType => - val tp1a = wildApprox(tp.tp1) - val tp2a = wildApprox(tp.tp2) - if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType]) - WildcardType(tp1a.bounds | tp2a.bounds) - else - tp.derivedOrType(tp1a, tp2a) + def approxOr = { + val tp1a = wildApprox(tp.tp1, theMap, seen) + val tp2a = wildApprox(tp.tp2, theMap, seen) + if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType]) + WildcardType(tp1a.bounds | tp2a.bounds) + else + tp.derivedOrType(tp1a, tp2a) + } + approxOr case tp: LazyRef => WildcardType case tp: SelectionProto => - tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto), NoViewsAllowed) + tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto, theMap, seen), NoViewsAllowed) case tp: ViewProto => - tp.derivedViewProto(wildApprox(tp.argType), wildApprox(tp.resultType)) + tp.derivedViewProto( + wildApprox(tp.argType, theMap, seen), + wildApprox(tp.resultType, theMap, seen)) case _: ThisType | _: BoundType | NoPrefix => // default case, inlined for speed tp case _ => - (if (theMap != null) theMap else new WildApproxMap).mapOver(tp) + (if (theMap != null) theMap else new WildApproxMap(seen)).mapOver(tp) } @sharable object AssignProto extends UncachedGroundType with MatchAlways - private[ProtoTypes] class WildApproxMap(implicit ctx: Context) extends TypeMap { - def apply(tp: Type) = wildApprox(tp, this) + private[ProtoTypes] class WildApproxMap(val seen: Set[PolyParam])(implicit ctx: Context) extends TypeMap { + def apply(tp: Type) = wildApprox(tp, this, seen) } /** Dummy tree to be used as an argument of a FunProto or ViewProto type */ diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 5ea36986f..652c89094 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1879,7 +1879,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val args = (wtp.paramNames, wtp.paramTypes).zipped map { (pname, formal) => def implicitArgError(msg: String => String) = errors += (() => msg(em"parameter $pname of $methodStr")) - inferImplicitArg(formal, implicitArgError, tree.pos.endPos) + if (errors.nonEmpty) EmptyTree + else inferImplicitArg(formal.widenExpr, implicitArgError, tree.pos.endPos) } if (errors.nonEmpty) { // If there are several arguments, some arguments might already |