diff options
author | odersky <odersky@gmail.com> | 2017-02-25 19:13:58 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-25 19:13:58 +0100 |
commit | 8467e5551ec7733c876c6764db1601aedc9767b9 (patch) | |
tree | 40bfc3ad04c3bf42696c27a34a35bad686940af6 /compiler/src/dotty/tools/dotc/typer | |
parent | 8a0a4fbdb7fc118a44cbc3dbd85095093717e7b4 (diff) | |
parent | d8c7a7ae0e981a2abd9e973617ef575270dd30a5 (diff) | |
download | dotty-8467e5551ec7733c876c6764db1601aedc9767b9.tar.gz dotty-8467e5551ec7733c876c6764db1601aedc9767b9.tar.bz2 dotty-8467e5551ec7733c876c6764db1601aedc9767b9.zip |
Merge pull request #1993 from dotty-staging/add-lazy-implicits
Treat implicit by-name arguments as lazy values
Diffstat (limited to 'compiler/src/dotty/tools/dotc/typer')
-rw-r--r-- | compiler/src/dotty/tools/dotc/typer/Implicits.scala | 49 | ||||
-rw-r--r-- | compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 |
2 files changed, 43 insertions, 8 deletions
diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 48cf0cfac..d5afae90c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -29,6 +29,7 @@ import reporting.diagnostic.MessageContainer import Inferencing.fullyDefinedType import Trees._ import Hashable._ +import util.Property import config.Config import config.Printers.{implicits, implicitsDetailed, typr} import collection.mutable @@ -36,6 +37,11 @@ import collection.mutable /** Implicit resolution */ object Implicits { + /** A reference to an implicit value to be made visible on the next nested call to + * inferImplicitArg with a by-name expected type. + */ + val DelayedImplicit = new Property.Key[TermRef] + /** An eligible implicit candidate, consisting of an implicit reference and a nesting level */ case class Candidate(ref: TermRef, level: Int) @@ -202,7 +208,7 @@ object Implicits { } override def toString = { - val own = s"(implicits: ${refs mkString ","})" + val own = i"(implicits: $refs%, %)" if (isOuterMost) own else own + "\n " + outerImplicits } @@ -537,27 +543,56 @@ trait Implicits { self: Typer => else EmptyTree } - inferImplicit(formal, EmptyTree, pos) match { + /** The context to be used when resolving a by-name implicit argument. + * This makes any implicit stored under `DelayedImplicit` visible and + * stores in turn the given `lazyImplicit` as new `DelayedImplicit`. + */ + def lazyImplicitCtx(lazyImplicit: Symbol): Context = { + val lctx = ctx.fresh + for (delayedRef <- ctx.property(DelayedImplicit)) + lctx.setImplicits(new ContextualImplicits(delayedRef :: Nil, ctx.implicits)(ctx)) + lctx.setProperty(DelayedImplicit, lazyImplicit.termRef) + } + + /** formalValue: The value type for which an implicit is searched + * lazyImplicit: An implicit symbol to install for nested by-name resolutions + * argCtx : The context to be used for searching the implicit argument + */ + val (formalValue, lazyImplicit, argCtx) = formal match { + case ExprType(fv) => + val lazyImplicit = ctx.newLazyImplicit(fv) + (fv, lazyImplicit, lazyImplicitCtx(lazyImplicit)) + case _ => (formal, NoSymbol, ctx) + } + + inferImplicit(formalValue, EmptyTree, pos)(argCtx) match { case SearchSuccess(arg, _, _, _) => - arg + def refersToLazyImplicit = arg.existsSubTree { + case id: Ident => id.symbol == lazyImplicit + case _ => false + } + if (lazyImplicit.exists && refersToLazyImplicit) + Block(ValDef(lazyImplicit.asTerm, arg).withPos(pos) :: Nil, ref(lazyImplicit)) + else + arg case ambi: AmbiguousImplicits => error(where => s"ambiguous implicits: ${ambi.explanation} of $where") EmptyTree case failure: SearchFailure => - val arg = synthesizedClassTag(formal, pos) + val arg = synthesizedClassTag(formalValue, pos) if (!arg.isEmpty) arg else { var msgFn = (where: String) => em"no implicit argument of type $formal found for $where" + failure.postscript for { - notFound <- formal.typeSymbol.getAnnotation(defn.ImplicitNotFoundAnnot) + notFound <- formalValue.typeSymbol.getAnnotation(defn.ImplicitNotFoundAnnot) Trees.Literal(Constant(raw: String)) <- notFound.argument(0) } { msgFn = where => err.implicitNotFoundString( raw, - formal.typeSymbol.typeParams.map(_.name.unexpandedName.toString), - formal.argInfos) + formalValue.typeSymbol.typeParams.map(_.name.unexpandedName.toString), + formalValue.argInfos) } error(msgFn) EmptyTree diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 06200d3e4..33e320ce5 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1890,7 +1890,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def implicitArgError(msg: String => String) = errors += (() => msg(em"parameter $pname of $methodStr")) if (errors.nonEmpty) EmptyTree - else inferImplicitArg(formal.widenExpr, implicitArgError, tree.pos.endPos) + else inferImplicitArg(formal, implicitArgError, tree.pos.endPos) } if (errors.nonEmpty) { // If there are several arguments, some arguments might already |