diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index df6f73e623ea..4e506dfd7864 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -182,14 +182,13 @@ class ReifyQuotes extends MacroTransform { capturers(body.symbol)(body) case _=> val (body1, splices) = nested(isQuote = true).splitQuote(body)(quoteContext) - if (level == 0 && !ctx.inInlineMethod) { + if (level == 0) { val body2 = if (body1.isType) body1 else Inlined(Inliner.inlineCallTrace(ctx.owner, quote.sourcePos), Nil, body1) pickledQuote(body2, splices, body.tpe, isType).withSpan(quote.span) } else { - // In top-level splice in an inline def. Keep the tree as it is, it will be transformed at inline site. body } } diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index d73a217b2a08..ca5d94dba23b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -217,29 +217,6 @@ object Applications { class ExtMethodApply(app: Tree)(implicit @constructorOnly src: SourceFile) extends IntegratedTypeArgs(app) - /** 1. If we are in an inline method but not in a nested quote, mark the inline method - * as a macro. - * - * 2. If selection is a quote or splice node, record that fact in the current compilation unit. - */ - def handleMeta(tree: Tree)(implicit ctx: Context): tree.type = { - import transform.SymUtils._ - - def markAsMacro(c: Context): Unit = - if (c.owner eq c.outer.owner) markAsMacro(c.outer) - else if (c.owner.isInlineMethod) c.owner.setFlag(Macro) - else if (!c.outer.owner.is(Package)) markAsMacro(c.outer) - val sym = tree.symbol - if (sym.isSplice) { - if (StagingContext.level == 0) - markAsMacro(ctx) - ctx.compilationUnit.needsStaging = true - } else if (sym.isQuote) { - ctx.compilationUnit.needsStaging = true - } - - tree - } } trait Applications extends Compatibility { self: Typer with Dynamic => @@ -820,7 +797,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => * or, if application is an operator assignment, also an `Assign` or * Block node. */ - def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = handleMeta { + def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { def realApply(implicit ctx: Context): Tree = track("realApply") { val originalProto = new FunProto(tree.args, IgnoredProto(pt))(this, tree.isContextual)(argCtx(tree)) @@ -964,7 +941,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => val isNamed = hasNamedArg(tree.args) val typedArgs = if (isNamed) typedNamedArgs(tree.args) else tree.args.mapconserve(typedType(_)) record("typedTypeApply") - handleMeta(typedFunPart(tree.fun, PolyProto(typedArgs, pt)) match { + typedFunPart(tree.fun, PolyProto(typedArgs, pt)) match { case IntegratedTypeArgs(app) => app case _: TypeApply if !ctx.isAfterTyper => @@ -986,7 +963,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => } if (typedFn.tpe eq TryDynamicCallType) tryDynamicTypeApply() else assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs) - }) + } } /** Rewrite `new Array[T](....)` if T is an unbounded generic to calls to newGenericArray. diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 3445e7811871..c488f915013b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -667,29 +667,36 @@ trait Implicits { self: Typer => EmptyTree } - def synthesizedTypeTag(formal: Type): Tree = formal.argInfos match { - case arg :: Nil if !arg.typeSymbol.is(Param) => - object bindFreeVars extends TypeMap { - var ok = true - def apply(t: Type) = t match { - case t @ TypeRef(NoPrefix, _) => - inferImplicit(defn.QuotedTypeType.appliedTo(t), EmptyTree, span) match { - case SearchSuccess(tag, _, _) if tag.tpe.isStable => - tag.tpe.select(defn.QuotedType_splice) - case _ => - ok = false - t - } - case _ => t + def synthesizedTypeTag(formal: Type): Tree = { + def quotedType(t: Type) = { + if (StagingContext.level == 0) + ctx.compilationUnit.needsStaging = true // We will need to run ReifyQuotes + ref(defn.InternalQuoted_typeQuote).appliedToType(t) + } + formal.argInfos match { + case arg :: Nil if !arg.typeSymbol.is(Param) => + object bindFreeVars extends TypeMap { + var ok = true + def apply(t: Type) = t match { + case t @ TypeRef(NoPrefix, _) => + inferImplicit(defn.QuotedTypeType.appliedTo(t), EmptyTree, span) match { + case SearchSuccess(tag, _, _) if tag.tpe.isStable => + tag.tpe.select(defn.QuotedType_splice) + case _ => + ok = false + t + } + case _ => t + } } - } - val tag = bindFreeVars(arg) - if (bindFreeVars.ok) ref(defn.InternalQuoted_typeQuote).appliedToType(tag) - else EmptyTree - case arg :: Nil if ctx.inInlineMethod => - ref(defn.InternalQuoted_typeQuote).appliedToType(arg) - case _ => - EmptyTree + val tag = bindFreeVars(arg) + if (bindFreeVars.ok) quotedType(tag) + else EmptyTree + case arg :: Nil if ctx.inInlineMethod => + quotedType(arg) + case _ => + EmptyTree + } } def synthesizedTastyContext(formal: Type): Tree = diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 0af0d7b409ee..90523de12f6a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -449,8 +449,7 @@ class Typer extends Namer } case qual => if (tree.name.isTypeName) checkStable(qual.tpe, qual.sourcePos) - val select = Applications.handleMeta( - checkValue(assignType(cpy.Select(tree)(qual, tree.name), qual), pt)) + val select = checkValue(assignType(cpy.Select(tree)(qual, tree.name), qual), pt) if (select.tpe ne TryDynamicCallType) ConstFold(checkStableIdentPattern(select, pt)) else if (pt.isInstanceOf[FunOrPolyProto] || pt == AssignProto) select else typedDynamicSelect(tree, Nil, pt) @@ -1936,8 +1935,10 @@ class Typer extends Namer ctx.warning("Canceled splice directly inside a quote. '{ ${ XYZ } } is equivalent to XYZ.", tree.sourcePos) typed(innerExpr, pt) case quoted if quoted.isType => + ctx.compilationUnit.needsStaging = true typedTypeApply(untpd.TypeApply(untpd.ref(defn.InternalQuoted_typeQuoteR), quoted :: Nil), pt)(quoteContext).withSpan(tree.span) case quoted => + ctx.compilationUnit.needsStaging = true if (ctx.mode.is(Mode.Pattern) && level == 0) { val exprPt = pt.baseType(defn.QuotedExprClass) val quotedPt = if (exprPt.exists) exprPt.argTypesHi.head else defn.AnyType @@ -2012,6 +2013,7 @@ class Typer extends Namer ctx.warning("Canceled quote directly inside a splice. ${ '{ XYZ } } is equivalent to XYZ.", tree.sourcePos) typed(innerExpr, pt) case expr => + ctx.compilationUnit.needsStaging = true if (ctx.mode.is(Mode.QuotedPattern) && level == 1) { if (isFullyDefined(pt, ForceDegree.all)) { def spliceOwner(ctx: Context): Symbol = @@ -2024,13 +2026,23 @@ class Typer extends Namer tree.withType(UnspecifiedErrorType) } } - else + else { + if (StagingContext.level == 0) { + // Mark the first inline method from the context as a macro + def markAsMacro(c: Context): Unit = + if (c.owner eq c.outer.owner) markAsMacro(c.outer) + else if (c.owner.isInlineMethod) c.owner.setFlag(Macro) + else if (!c.outer.owner.is(Package)) markAsMacro(c.outer) + markAsMacro(ctx) + } typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprSpliceR), tree.expr), pt)(spliceContext).withSpan(tree.span) + } } } /** Translate ${ t: Type[T] }` into type `t.splice` while tracking the quotation level in the context */ def typedTypSplice(tree: untpd.TypSplice, pt: Type)(implicit ctx: Context): Tree = track("typedTypSplice") { + ctx.compilationUnit.needsStaging = true checkSpliceOutsideQuote(tree) typedSelect(untpd.Select(tree.expr, tpnme.splice), pt)(spliceContext).withSpan(tree.span) } diff --git a/compiler/test-resources/repl/i6263 b/compiler/test-resources/repl/i6263 new file mode 100644 index 000000000000..8a9047cc2b85 --- /dev/null +++ b/compiler/test-resources/repl/i6263 @@ -0,0 +1,13 @@ +scala> import quoted._ +scala> def fn[T : Type](v : T) = println("ok") +def fn[T](v: T)(implicit evidence$1: quoted.Type[T]): Unit +scala> fn("foo") +ok +scala> fn((1,2)) +ok +scala> object O +// defined object O +scala> fn(O) +ok +scala> fn(1) +ok diff --git a/tests/run-with-compiler/i6263.scala b/tests/run-with-compiler/i6263.scala new file mode 100644 index 000000000000..b940c1c61d37 --- /dev/null +++ b/tests/run-with-compiler/i6263.scala @@ -0,0 +1,14 @@ +import quoted._ +object Test { + + def main(args: Array[String]): Unit = { + fn("foo") + fn((1,2)) + fn(O) + fn(1) + } + + def fn[T : Type](v : T) = "ok" +} + +object O