From b2633f91eb8a960d62614054b830990b61786377 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 4 Nov 2018 11:30:31 +0100 Subject: [PATCH 1/6] Go back to inlining during typing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverts the following commits: Join containsQuotesOrSplices and containsInlineCalls (reverted from commit 8cf1385fc956a8d4ca12e14527301e3272c96d41) Make InlineCalls an object (reverted from commit ad26554411b9c5b340e96f99c33beb299a7170fa) Remove Inlined and InlineProxy from TASTy (reverted from commit 976e095fd79e7811132b6d85066bbe6253d33bad) Move inlining inside Reify quotes Split some neg tests as now only the first error is emitted. (reverted from commit 21e65f1e4256ae4eb097e84a668ae5ab94cd0744) Erase rhs of erased non inlined val/def in PostTyper (reverted from commit c12e8753f3dccc6b0bc3b84f19e8160434c340c8) Add isInlineCall to TreeInfo (reverted from commit 954c25b3ae85c2f6c68eb4ae209b616f0f987e67) Update doc (reverted from commit 0832e027208830d61e1efba0ca82dfcdad608114) Only run InlineCalls if the tree contains an inline call (reverted from commit f28e2e1ee566bbc5a8a77c1a6345e6b779b311f3) Check if unpickled tree has inline nodes (reverted from commit 927ae4e60c58318336d493b4c4ecc29ec88242e4) Add a bit of documentation (reverted from commit da0c2493cbedf82081ca071363f2713aa5928e89) Fix constant folding during inlining (reverted from commit 32c8798153276a428bd4a1bc7b3e4f924e1f0489) Move inline β-reduction after Pickler (reverted from commit c68dc1f5ace7486339af1d55884677459d0e85fd) Normalize call at Inlined node creation (reverted from commit 746fdd7831a588066f2cfc1c64a000df79d40b63) Move inline β-reduction after post typer (reverted from commit 432eb0a8e2a320e72517cf68c622f0300d221f12) Move inline β-reduction out of typer (reverted from commit 6acaf31eafca43fb14d566b3eef85c5132005b02) --- .../dotty/tools/dotc/CompilationUnit.scala | 9 +- compiler/src/dotty/tools/dotc/Compiler.scala | 2 +- .../src/dotty/tools/dotc/ast/TreeInfo.scala | 10 +- compiler/src/dotty/tools/dotc/ast/Trees.scala | 5 +- .../tools/dotc/core/tasty/TastyFormat.scala | 105 ++++++++++-------- .../tools/dotc/core/tasty/TreePickler.scala | 12 ++ .../tools/dotc/core/tasty/TreeUnpickler.scala | 12 ++ .../dotc/decompiler/TASTYDecompiler.scala | 1 - .../tools/dotc/transform/PostTyper.scala | 38 ++++--- .../dotty/tools/dotc/transform/Staging.scala | 36 +----- .../src/dotty/tools/dotc/typer/Inliner.scala | 11 +- .../src/dotty/tools/dotc/typer/Typer.scala | 7 ++ compiler/test/dotc/pos-from-tasty.blacklist | 5 +- .../test/dotc/pos-recompilation.whitelist | 1 + .../test/dotc/run-test-pickling.blacklist | 1 + .../quote-run-in-macro-2/quoted_2.scala | 6 + .../quote-run-in-macro-3/quoted_1.scala | 11 -- .../quote-run-in-macro-3/quoted_2.scala | 6 - .../quote-run-in-macro-4/quoted_1.scala | 11 -- .../quote-run-in-macro-4/quoted_2.scala | 9 -- tests/neg/tasty-macro-assert-2/quoted_1.scala | 69 ------------ tests/neg/tasty-macro-assert-2/quoted_2.scala | 10 -- tests/neg/tasty-macro-assert/quoted_2.scala | 2 + tests/pos/simpleInline.decompiled | 4 +- .../tasty-extractors-owners.check | 4 +- tests/run-with-compiler/i3876-d.check | 2 +- 26 files changed, 143 insertions(+), 246 deletions(-) delete mode 100644 tests/neg-with-compiler/quote-run-in-macro-3/quoted_1.scala delete mode 100644 tests/neg-with-compiler/quote-run-in-macro-3/quoted_2.scala delete mode 100644 tests/neg-with-compiler/quote-run-in-macro-4/quoted_1.scala delete mode 100644 tests/neg-with-compiler/quote-run-in-macro-4/quoted_2.scala delete mode 100644 tests/neg/tasty-macro-assert-2/quoted_1.scala delete mode 100644 tests/neg/tasty-macro-assert-2/quoted_2.scala diff --git a/compiler/src/dotty/tools/dotc/CompilationUnit.scala b/compiler/src/dotty/tools/dotc/CompilationUnit.scala index c275fb25ca66..00527db565a8 100644 --- a/compiler/src/dotty/tools/dotc/CompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/CompilationUnit.scala @@ -3,14 +3,12 @@ package dotc import util.SourceFile import ast.{tpd, untpd} -import dotty.tools.dotc.ast.Trees import tpd.{Tree, TreeTraverser} import typer.PrepareInlineable.InlineAccessors import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.core.SymDenotations.ClassDenotation import dotty.tools.dotc.core.Symbols._ import dotty.tools.dotc.transform.SymUtils._ -import dotty.tools.dotc.typer.Inliner class CompilationUnit(val source: SourceFile) { @@ -25,8 +23,8 @@ class CompilationUnit(val source: SourceFile) { /** Pickled TASTY binaries, indexed by class. */ var pickled: Map[ClassSymbol, Array[Byte]] = Map() - /** Will be set to `true` if contains `Quote`, `Splice` or calls to inline methods. - * The information is used in phase `Staging` in order to avoid traversing a quote-less tree. + /** Will be set to `true` if contains `Quote`. + * The information is used in phase `Staging` in order to avoid traversing trees that need no transformations. */ var needsStaging: Boolean = false @@ -57,8 +55,7 @@ object CompilationUnit { private class Force extends TreeTraverser { var needsStaging = false def traverse(tree: Tree)(implicit ctx: Context): Unit = { - // Note that top-level splices are still inside the inline methods - if (tree.symbol.isQuote || tpd.isInlineCall(tree)) + if (tree.symbol.isQuote) needsStaging = true traverseChildren(tree) } diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index ec2a870e8c87..aeb063767e65 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -44,7 +44,7 @@ class Compiler { /** Phases dealing with TASTY tree pickling and unpickling */ protected def picklerPhases: List[List[Phase]] = List(new Pickler) :: // Generate TASTY info - List(new Staging) :: // Inline calls, expand macros and turn quoted trees into explicit run-time data structures + List(new Staging) :: // Turn quoted trees into explicit run-time data structures Nil /** Phases dealing with the transformation from pickled trees to backend trees */ diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index 5daee6fc9b46..01f8d21259db 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -5,7 +5,7 @@ package ast import core._ import Flags._, Trees._, Types._, Contexts._ import Names._, StdNames._, NameOps._, Symbols._ -import typer.{ConstFold, Inliner} +import typer.ConstFold import reporting.trace import scala.annotation.tailrec @@ -770,14 +770,6 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => false } - /** Is this call a call to a method that is marked as Inline */ - def isInlineCall(arg: Tree)(implicit ctx: Context): Boolean = arg match { - case _: RefTree | _: GenericApply[_] => - !arg.tpe.widenDealias.isInstanceOf[MethodicType] && Inliner.isInlineable(arg) - case _ => - false - } - /** Structural tree comparison (since == on trees is reference equality). * For the moment, only Ident, Select, Literal, Apply and TypeApply are supported */ diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 10b5e93723bf..8206e8dcd763 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -585,8 +585,9 @@ object Trees { /** A tree representing inlined code. * - * @param call Info about the original call that was inlined. - * Only a reference to the toplevel class from which the call was inlined. + * @param call Info about the original call that was inlined + * Until PostTyper, this is the full call, afterwards only + * a reference to the toplevel class from which the call was inlined. * @param bindings Bindings for proxies to be used in the inlined code * @param expansion The inlined tree, minus bindings. * diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 09f02b2ff6b9..a983bee8b9f7 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -86,6 +86,7 @@ Standard-Section: "ASTs" TopLevelStat* TYPED Length expr_Term ascriptionType_Tern ASSIGN Length lhs_Term rhs_Term BLOCK Length expr_Term Stat* + INLINED Length expr_Term call_Term? ValOrDefDef* LAMBDA Length meth_Term target_Type? IF Length cond_Term then_Term else_Term MATCH Length sel_Term CaseDef* @@ -184,6 +185,7 @@ Standard-Section: "ASTs" TopLevelStat* OVERRIDE INLINE MACRO // inline method containing toplevel splices + INLINEPROXY // symbol of binding representing an inline parameter STATIC // mapped to static Java member OBJECT // an object or its class TRAIT // a trait @@ -233,7 +235,7 @@ Standard Section: "Comments" Comment* object TastyFormat { final val header: Array[Int] = Array(0x5C, 0xA1, 0xAB, 0x1F) - val MajorVersion: Int = 13 + val MajorVersion: Int = 11 val MinorVersion: Int = 0 /** Tags used to serialize names */ @@ -286,25 +288,26 @@ object TastyFormat { final val IMPLICIT = 13 final val LAZY = 14 final val OVERRIDE = 15 - final val INLINE = 16 - final val STATIC = 17 - final val OBJECT = 18 - final val TRAIT = 19 - final val ENUM = 20 - final val LOCAL = 21 - final val SYNTHETIC = 22 - final val ARTIFACT = 23 - final val MUTABLE = 24 - final val FIELDaccessor = 25 - final val CASEaccessor = 26 - final val COVARIANT = 27 - final val CONTRAVARIANT = 28 - final val SCALA2X = 29 - final val DEFAULTparameterized = 30 - final val STABLE = 31 - final val MACRO = 32 - final val ERASED = 33 - final val PARAMsetter = 34 + final val INLINEPROXY = 16 + final val INLINE = 17 + final val STATIC = 18 + final val OBJECT = 19 + final val TRAIT = 20 + final val ENUM = 21 + final val LOCAL = 22 + final val SYNTHETIC = 23 + final val ARTIFACT = 24 + final val MUTABLE = 25 + final val FIELDaccessor = 26 + final val CASEaccessor = 27 + final val COVARIANT = 28 + final val CONTRAVARIANT = 29 + final val SCALA2X = 30 + final val DEFAULTparameterized = 31 + final val STABLE = 32 + final val MACRO = 33 + final val ERASED = 34 + final val PARAMsetter = 35 // Cat. 2: tag Nat @@ -378,35 +381,36 @@ object TastyFormat { final val RETURN = 144 final val WHILE = 145 final val TRY = 146 - final val SELECTouter = 147 - final val REPEATED = 148 - final val BIND = 149 - final val ALTERNATIVE = 150 - final val UNAPPLY = 151 - final val ANNOTATEDtype = 152 - final val ANNOTATEDtpt = 153 - final val CASEDEF = 154 - final val TEMPLATE = 155 - final val SUPER = 156 - final val SUPERtype = 157 - final val REFINEDtype = 158 - final val REFINEDtpt = 159 - final val APPLIEDtype = 160 - final val APPLIEDtpt = 161 - final val TYPEBOUNDS = 162 - final val TYPEBOUNDStpt = 163 - final val ANDtype = 164 - final val ANDtpt = 165 - final val ORtype = 166 - final val ORtpt = 167 - final val POLYtype = 168 - final val TYPELAMBDAtype = 169 - final val LAMBDAtpt = 170 - final val PARAMtype = 171 - final val ANNOTATION = 172 - final val TERMREFin = 173 - final val TYPEREFin = 174 - final val OBJECTDEF = 175 + final val INLINED = 147 + final val SELECTouter = 148 + final val REPEATED = 149 + final val BIND = 150 + final val ALTERNATIVE = 151 + final val UNAPPLY = 152 + final val ANNOTATEDtype = 153 + final val ANNOTATEDtpt = 154 + final val CASEDEF = 155 + final val TEMPLATE = 156 + final val SUPER = 157 + final val SUPERtype = 158 + final val REFINEDtype = 159 + final val REFINEDtpt = 160 + final val APPLIEDtype = 161 + final val APPLIEDtpt = 162 + final val TYPEBOUNDS = 163 + final val TYPEBOUNDStpt = 164 + final val ANDtype = 165 + final val ANDtpt = 166 + final val ORtype = 167 + final val ORtpt = 168 + final val POLYtype = 169 + final val TYPELAMBDAtype = 170 + final val LAMBDAtpt = 171 + final val PARAMtype = 172 + final val ANNOTATION = 173 + final val TERMREFin = 174 + final val TYPEREFin = 175 + final val OBJECTDEF = 176 // In binary: 101101EI // I = implicit method type @@ -456,6 +460,7 @@ object TastyFormat { | LAZY | OVERRIDE | INLINE + | INLINEPROXY | MACRO | STATIC | OBJECT @@ -512,6 +517,7 @@ object TastyFormat { case LAZY => "LAZY" case OVERRIDE => "OVERRIDE" case INLINE => "INLINE" + case INLINEPROXY => "INLINEPROXY" case MACRO => "MACRO" case STATIC => "STATIC" case OBJECT => "OBJECT" @@ -579,6 +585,7 @@ object TastyFormat { case MATCH => "MATCH" case RETURN => "RETURN" case WHILE => "WHILE" + case INLINED => "INLINED" case SELECTouter => "SELECTouter" case TRY => "TRY" case REPEATED => "REPEATED" diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 217c88012f2d..a4ca4a48e59f 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -442,6 +442,17 @@ class TreePickler(pickler: TastyPickler) { case SeqLiteral(elems, elemtpt) => writeByte(REPEATED) withLength { pickleTree(elemtpt); elems.foreach(pickleTree) } + case Inlined(call, bindings, expansion) => + writeByte(INLINED) + bindings.foreach(preRegister) + withLength { + pickleTree(expansion) + if (!call.isEmpty) pickleTree(call) + bindings.foreach { b => + assert(b.isInstanceOf[DefDef] || b.isInstanceOf[ValDef]) + pickleTree(b) + } + } case Bind(name, body) => registerDef(tree.symbol) writeByte(BIND) @@ -608,6 +619,7 @@ class TreePickler(pickler: TastyPickler) { if (flags is Case) writeByte(CASE) if (flags is Override) writeByte(OVERRIDE) if (flags is Inline) writeByte(INLINE) + if (flags is InlineProxy) writeByte(INLINEPROXY) if (flags is Macro) writeByte(MACRO) if (flags is JavaStatic) writeByte(STATIC) if (flags is Module) writeByte(OBJECT) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 019c3649752c..03851740c810 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -604,6 +604,7 @@ class TreeUnpickler(reader: TastyReader, case LAZY => addFlag(Lazy) case OVERRIDE => addFlag(Override) case INLINE => addFlag(Inline) + case INLINEPROXY => addFlag(InlineProxy) case MACRO => addFlag(Macro) case STATIC => addFlag(JavaStatic) case OBJECT => addFlag(Module) @@ -1072,6 +1073,17 @@ class TreeUnpickler(reader: TastyReader, val stats = readStats(ctx.owner, end) val expr = exprReader.readTerm() Block(stats, expr) + case INLINED => + val exprReader = fork + skipTree() + def maybeCall = nextUnsharedTag match { + case VALDEF | DEFDEF => EmptyTree + case _ => readTerm() + } + val call = ifBefore(end)(maybeCall, EmptyTree) + val bindings = readStats(ctx.owner, end).asInstanceOf[List[ValOrDefDef]] + val expansion = exprReader.readTerm() // need bindings in scope, so needs to be read before + Inlined(call, bindings, expansion) case IF => If(readTerm(), readTerm(), readTerm()) case LAMBDA => diff --git a/compiler/src/dotty/tools/dotc/decompiler/TASTYDecompiler.scala b/compiler/src/dotty/tools/dotc/decompiler/TASTYDecompiler.scala index 62627a6b050a..4601ff9d1a12 100644 --- a/compiler/src/dotty/tools/dotc/decompiler/TASTYDecompiler.scala +++ b/compiler/src/dotty/tools/dotc/decompiler/TASTYDecompiler.scala @@ -15,7 +15,6 @@ class TASTYDecompiler extends TASTYCompiler { Nil override protected def picklerPhases: List[List[Phase]] = Nil - override protected def transformPhases: List[List[Phase]] = Nil override protected def backendPhases: List[List[Phase]] = diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 3c99b15347c7..355bf11bc3d1 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -40,7 +40,8 @@ object PostTyper { * * (10) Adds Child annotations to all sealed classes * - * (11) Replace RHS of `erased` (but not `inline`) members by `(???: rhs.type)` + * (11) Minimizes `call` fields of `Inlined` nodes to just point to the toplevel + * class from which code was inlined. * * The reason for making this a macro transform is that some functions (in particular * super and protected accessors and instantiation checks) are naturally top-down and @@ -177,22 +178,23 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase } } - private def handleInlineCall(sym: Symbol)(implicit ctx: Context): Unit = { - if (sym.is(Inline)) - ctx.compilationUnit.needsStaging = true + private object dropInlines extends TreeMap { + override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match { + case Inlined(call, _, _) => + cpy.Inlined(tree)(call, Nil, Typed(ref(defn.Predef_undefined), TypeTree(tree.tpe))) + case _ => super.transform(tree) + } } override def transform(tree: Tree)(implicit ctx: Context): Tree = try tree match { case tree: Ident if !tree.isType => - handleInlineCall(tree.symbol) handleMeta(tree.symbol) tree.tpe match { case tpe: ThisType => This(tpe.cls).withPos(tree.pos) case _ => tree } case tree @ Select(qual, name) => - handleInlineCall(tree.symbol) handleMeta(tree.symbol) if (name.isTypeName) { Checking.checkRealizable(qual.tpe, qual.pos.focus) @@ -201,7 +203,6 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase else transformSelect(tree, Nil) case tree: Apply => - handleInlineCall(tree.symbol) val methType = tree.fun.tpe.widen val app = if (methType.isErasedMethod) @@ -209,7 +210,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase tree.fun, tree.args.map(arg => if (methType.isImplicitMethod && arg.pos.isSynthetic) ref(defn.Predef_undefined) - else arg)) + else dropInlines.transform(arg))) else tree methPart(app) match { @@ -222,7 +223,6 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase super.transform(app) } case tree: TypeApply => - handleInlineCall(tree.symbol) val tree1 @ TypeApply(fn, args) = normalizeTypeArgs(tree) if (fn.symbol != defn.ChildAnnot.primaryConstructor) { // Make an exception for ChildAnnot, which should really have AnyKind bounds @@ -236,6 +236,19 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case _ => super.transform(tree1) } + case Inlined(call, bindings, expansion) if !call.isEmpty => + // Leave only a call trace consisting of + // - a reference to the top-level class from which the call was inlined, + // - the call's position + // in the call field of an Inlined node. + // The trace has enough info to completely reconstruct positions. + // The minimization is done for two reasons: + // 1. To save space (calls might contain large inline arguments, which would otherwise + // be duplicated + // 2. To enable correct pickling (calls can share symbols with the inlined code, which + // would trigger an assertion when pickling). + val callTrace = Ident(call.symbol.topLevelClass.typeRef).withPos(call.pos) + cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(inlineContext(call))) case tree: Template => withNoCheckNews(tree.parents.flatMap(newPart)) { val templ1 = paramFwd.forwardParamAccessors(tree) @@ -322,10 +335,9 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase } /** Transforms the rhs tree into a its default tree if it is in an `erased` val/def. - * Performed to shrink the tree that is known to be erased later. - */ + * Performed to shrink the tree that is known to be erased later. + */ private def normalizeErasedRhs(rhs: Tree, sym: Symbol)(implicit ctx: Context) = - if (!sym.isEffectivelyErased || sym.isInlineMethod || !rhs.tpe.exists) rhs - else Typed(ref(defn.Predef_undefined), TypeTree(rhs.tpe)) + if (sym.isEffectivelyErased) dropInlines.transform(rhs) else rhs } } diff --git a/compiler/src/dotty/tools/dotc/transform/Staging.scala b/compiler/src/dotty/tools/dotc/transform/Staging.scala index f94b422a5670..90a727e0eec8 100644 --- a/compiler/src/dotty/tools/dotc/transform/Staging.scala +++ b/compiler/src/dotty/tools/dotc/transform/Staging.scala @@ -2,12 +2,7 @@ package dotty.tools.dotc package transform import core._ -import Decorators._ -import Flags._ -import Types._ -import Contexts._ -import Symbols._ -import Constants._ +import Decorators._, Flags._, Types._, Contexts._, Symbols._, Constants._ import ast.Trees._ import ast.{TreeTypeMap, untpd} import util.Positions._ @@ -20,12 +15,11 @@ import typer.Implicits.SearchFailureType import scala.collection.mutable import dotty.tools.dotc.core.StdNames._ import dotty.tools.dotc.core.quoted._ -import dotty.tools.dotc.typer.{ConstFold, Inliner} import dotty.tools.dotc.util.SourcePosition -/** Inline calls to inline methods, evaluates macros, translates quoted terms (and types) - * to `unpickle` method calls and checks that the phase consistency principle (PCP) holds. +/** Translates quoted terms and types to `unpickle` method calls. + * Checks that the phase consistency principle (PCP) holds. * * * Transforms top level quote @@ -443,8 +437,7 @@ class Staging extends MacroTransformWithImplicits { else if (enclosingInlineds.nonEmpty) { // level 0 in an inlined call val spliceCtx = ctx.outer // drop the last `inlineContext` val pos: SourcePosition = Decorators.sourcePos(enclosingInlineds.head.pos)(spliceCtx) - val splicedTree = InlineCalls.transform(splice.qualifier) // inline calls that where inlined at level -1 - val evaluatedSplice = Splicer.splice(splicedTree, pos, macroClassLoader)(spliceCtx).withPos(splice.pos) + val evaluatedSplice = Splicer.splice(splice.qualifier, pos, macroClassLoader)(spliceCtx).withPos(splice.pos) if (ctx.reporter.hasErrors) splice else transform(evaluatedSplice) } else if (!ctx.owner.isInlineMethod) { // level 0 outside an inline method @@ -567,9 +560,6 @@ class Staging extends MacroTransformWithImplicits { enteredSyms = enteredSyms.tail } tree match { - case tree if isInlineCall(tree) && level == 0 && !ctx.reporter.hasErrors && !ctx.settings.YnoInline.value => - val tree2 = super.transform(tree) // transform arguments before inlining (inline arguments and constant fold arguments) - transform(Inliner.inlineCall(tree2, tree.tpe.widen)) case Quoted(quotedTree) => quotation(quotedTree, tree) case tree: TypeTree if tree.tpe.typeSymbol.isSplice => @@ -620,7 +610,7 @@ class Staging extends MacroTransformWithImplicits { } case _ => markDef(tree) - ConstFold(checkLevel(mapOverTree(enteredSyms))) + checkLevel(mapOverTree(enteredSyms)) } } @@ -676,20 +666,4 @@ object Staging { /** Get the list of embedded trees */ def getTrees: List[tpd.Tree] = trees.toList } - - /** β-reduce all calls to inline methods and preform constant folding */ - object InlineCalls extends TreeMap { - override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match { - case tree if isInlineCall(tree) && !ctx.reporter.hasErrors && !ctx.settings.YnoInline.value => - val tree2 = super.transform(tree) // transform arguments before inlining (inline arguments and constant fold arguments) - transform(Inliner.inlineCall(tree2, tree.tpe.widen)) - case _: MemberDef => - val newTree = super.transform(tree) - if (newTree.symbol.exists) - newTree.symbol.defTree = newTree // set for inlined members - newTree - case _ => - ConstFold(super.transform(tree)) - } - } } diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 1432c5405cad..933e7c10c81f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -455,18 +455,9 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { if (inlinedMethod == defn.Typelevel_error) issueError() - // Leave only a call trace consisting of - // - a reference to the top-level class from which the call was inlined, - // - the call's position - // in the call field of an Inlined node. - // The trace has enough info to completely reconstruct positions. - // The minimization is done for the following reason: - // * To save space (calls might contain large inline arguments, which would otherwise be duplicated - val callTrace = Ident(call.symbol.topLevelClass.typeRef).withPos(call.pos) - // Take care that only argument bindings go into `bindings`, since positions are // different for bindings from arguments and bindings from body. - tpd.Inlined(callTrace, finalBindings, finalExpansion) + tpd.Inlined(call, finalBindings, finalExpansion) } } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index c2fe93d32475..e673d99c0b1f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2454,6 +2454,13 @@ class Typer extends Namer checkEqualityEvidence(tree, pt) tree } + else if (Inliner.isInlineable(tree) && + !ctx.settings.YnoInline.value && + !ctx.isAfterTyper && + !ctx.reporter.hasErrors && + tree.tpe <:< pt) { + readaptSimplified(Inliner.inlineCall(tree, pt)) + } else if (tree.tpe <:< pt) { if (pt.hasAnnotation(defn.InlineParamAnnot)) checkInlineConformant(tree, isFinal = false, "argument to inline parameter") diff --git a/compiler/test/dotc/pos-from-tasty.blacklist b/compiler/test/dotc/pos-from-tasty.blacklist index ace498a34d3f..a48abcd017a0 100644 --- a/compiler/test/dotc/pos-from-tasty.blacklist +++ b/compiler/test/dotc/pos-from-tasty.blacklist @@ -17,7 +17,4 @@ repeatedArgs213.scala default-super.scala # Need to implement printing of match types -matchtype.scala - -# Fails on CI (not locally) -inline-named-typeargs.scala +matchtype.scala \ No newline at end of file diff --git a/compiler/test/dotc/pos-recompilation.whitelist b/compiler/test/dotc/pos-recompilation.whitelist index ef14a97f1d25..eb4c22b9d238 100644 --- a/compiler/test/dotc/pos-recompilation.whitelist +++ b/compiler/test/dotc/pos-recompilation.whitelist @@ -985,6 +985,7 @@ t8132 t8177d t8177e t8177h +t8207 t8219 t8230a t8237 diff --git a/compiler/test/dotc/run-test-pickling.blacklist b/compiler/test/dotc/run-test-pickling.blacklist index 672cee097820..db1a51b342b3 100644 --- a/compiler/test/dotc/run-test-pickling.blacklist +++ b/compiler/test/dotc/run-test-pickling.blacklist @@ -7,3 +7,4 @@ lazy-traits.scala t8133 t8133b tuples1.scala +tuples1a.scala diff --git a/tests/neg-with-compiler/quote-run-in-macro-2/quoted_2.scala b/tests/neg-with-compiler/quote-run-in-macro-2/quoted_2.scala index 6e40f84ec7f0..02a0925642f4 100644 --- a/tests/neg-with-compiler/quote-run-in-macro-2/quoted_2.scala +++ b/tests/neg-with-compiler/quote-run-in-macro-2/quoted_2.scala @@ -2,5 +2,11 @@ import Macros._ object Test { def main(args: Array[String]): Unit = { println(foo(1)) // error + println(foo(1 + 3)) // error + val x = 3 + println(foo { // error + val x = 5 + x + }) } } diff --git a/tests/neg-with-compiler/quote-run-in-macro-3/quoted_1.scala b/tests/neg-with-compiler/quote-run-in-macro-3/quoted_1.scala deleted file mode 100644 index a9daf7d26556..000000000000 --- a/tests/neg-with-compiler/quote-run-in-macro-3/quoted_1.scala +++ /dev/null @@ -1,11 +0,0 @@ -import scala.quoted._ - -import scala.quoted.Toolbox.Default._ - -object Macros { - inline def foo(i: => Int): Int = ~fooImpl('(i)) - def fooImpl(i: Expr[Int]): Expr[Int] = { - val y: Int = i.run - y.toExpr - } -} diff --git a/tests/neg-with-compiler/quote-run-in-macro-3/quoted_2.scala b/tests/neg-with-compiler/quote-run-in-macro-3/quoted_2.scala deleted file mode 100644 index 663912caa1e8..000000000000 --- a/tests/neg-with-compiler/quote-run-in-macro-3/quoted_2.scala +++ /dev/null @@ -1,6 +0,0 @@ -import Macros._ -object Test { - def main(args: Array[String]): Unit = { - println(foo(1 + 3)) // error - } -} diff --git a/tests/neg-with-compiler/quote-run-in-macro-4/quoted_1.scala b/tests/neg-with-compiler/quote-run-in-macro-4/quoted_1.scala deleted file mode 100644 index a9daf7d26556..000000000000 --- a/tests/neg-with-compiler/quote-run-in-macro-4/quoted_1.scala +++ /dev/null @@ -1,11 +0,0 @@ -import scala.quoted._ - -import scala.quoted.Toolbox.Default._ - -object Macros { - inline def foo(i: => Int): Int = ~fooImpl('(i)) - def fooImpl(i: Expr[Int]): Expr[Int] = { - val y: Int = i.run - y.toExpr - } -} diff --git a/tests/neg-with-compiler/quote-run-in-macro-4/quoted_2.scala b/tests/neg-with-compiler/quote-run-in-macro-4/quoted_2.scala deleted file mode 100644 index f5fa99aa13e6..000000000000 --- a/tests/neg-with-compiler/quote-run-in-macro-4/quoted_2.scala +++ /dev/null @@ -1,9 +0,0 @@ -import Macros._ -object Test { - def main(args: Array[String]): Unit = { - println(foo { // error - val x = 5 - x - }) - } -} diff --git a/tests/neg/tasty-macro-assert-2/quoted_1.scala b/tests/neg/tasty-macro-assert-2/quoted_1.scala deleted file mode 100644 index 59c7d29a4378..000000000000 --- a/tests/neg/tasty-macro-assert-2/quoted_1.scala +++ /dev/null @@ -1,69 +0,0 @@ -import scala.quoted._ - -import scala.tasty._ - -object Asserts { - - implicit class Ops[T](left: T) { - def ===(right: T): Boolean = left == right - def !==(right: T): Boolean = left != right - } - - object Ops - - inline def macroAssert(cond: => Boolean): Unit = - ~impl('(cond)) - - def impl(cond: Expr[Boolean])(implicit tasty: Tasty): Expr[Unit] = { - import tasty._ - - val tree = cond.toTasty - - def isOps(tpe: TypeOrBounds): Boolean = tpe match { - case Type.SymRef(IsDefSymbol(sym), _) => sym.name == "Ops" // TODO check that the parent is Asserts - case _ => false - } - - object OpsTree { - def unapply(arg: Term): Option[Term] = arg match { - case Term.Apply(Term.TypeApply(term, _), left :: Nil) if isOps(term.tpe) => - Some(left) - case _ => None - } - } - - tree match { - case Term.Inlined(_, Nil, Term.Apply(Term.Select(OpsTree(left), op, _), right :: Nil)) => - '(assertTrue(~left.toExpr[Boolean])) // Buggy code. To generate the errors - case _ => - '(assertTrue(~cond)) - } - - } - - def assertEquals[T](left: T, right: T): Unit = { - if (left != right) { - println( - s"""Error left did not equal right: - | left = $left - | right = $right""".stripMargin) - } - - } - - def assertNotEquals[T](left: T, right: T): Unit = { - if (left == right) { - println( - s"""Error left was equal to right: - | left = $left - | right = $right""".stripMargin) - } - - } - - def assertTrue(cond: Boolean): Unit = { - if (!cond) - println("Condition was false") - } - -} diff --git a/tests/neg/tasty-macro-assert-2/quoted_2.scala b/tests/neg/tasty-macro-assert-2/quoted_2.scala deleted file mode 100644 index b43e3cc84dde..000000000000 --- a/tests/neg/tasty-macro-assert-2/quoted_2.scala +++ /dev/null @@ -1,10 +0,0 @@ - -import Asserts._ - -object Test { - def main(args: Array[String]): Unit = { - macroAssert(false !== "acb") - macroAssert("acb" !== "acb") // error - } - -} diff --git a/tests/neg/tasty-macro-assert/quoted_2.scala b/tests/neg/tasty-macro-assert/quoted_2.scala index 25ef0291b120..b94c98ab6b70 100644 --- a/tests/neg/tasty-macro-assert/quoted_2.scala +++ b/tests/neg/tasty-macro-assert/quoted_2.scala @@ -5,6 +5,8 @@ object Test { def main(args: Array[String]): Unit = { macroAssert(true === "cde") macroAssert("acb" === "cde") // error + macroAssert(false !== "acb") + macroAssert("acb" !== "acb") // error } } diff --git a/tests/pos/simpleInline.decompiled b/tests/pos/simpleInline.decompiled index 7fa25f3b3720..492a0da6e777 100644 --- a/tests/pos/simpleInline.decompiled +++ b/tests/pos/simpleInline.decompiled @@ -1,5 +1,7 @@ /** Decompiled from out/posTestFromTasty/pos/simpleInline/Foo.class */ class Foo() { inline def foo: scala.Int = 9 - def bar: scala.Int = Foo.this.foo + def bar: scala.Int = { // inlined + 9 + } } diff --git a/tests/run-custom-args/Yretain-trees/tasty-extractors-owners.check b/tests/run-custom-args/Yretain-trees/tasty-extractors-owners.check index 690f56b6dba9..d541fcc56321 100644 --- a/tests/run-custom-args/Yretain-trees/tasty-extractors-owners.check +++ b/tests/run-custom-args/Yretain-trees/tasty-extractors-owners.check @@ -1,5 +1,5 @@ foo -DefDef("main", Nil, List(List(ValDef("args", TypeTree.Applied(TypeTree.Ident("Array"), List(TypeTree.Ident("String"))), None))), TypeTree.Ident("Unit"), Some(Term.Block(Nil, Term.Apply(Term.TypeApply(Term.Ident("printOwners"), List(TypeTree.Synthetic())), List(Term.Block(List(DefDef("foo", Nil, Nil, TypeTree.Synthetic(), Some(Term.Block(List(DefDef("bar", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(1)))), ValDef("bar2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(2))))), Term.Typed(Term.Ident("bar"), TypeTree.Synthetic())))), ValDef("foo2", TypeTree.Synthetic(), Some(Term.Block(List(DefDef("baz", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(3)))), ValDef("baz2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(4))))), Term.Typed(Term.Ident("baz"), TypeTree.Synthetic())))), ClassDef("A", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(TypeDef("B", TypeTree.Ident("Int")), DefDef("b", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(5)))), ValDef("b2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(6))))))), Term.Literal(Constant.Unit()))))))) +DefDef("main", Nil, List(List(ValDef("args", TypeTree.Applied(TypeTree.Ident("Array"), List(TypeTree.Ident("String"))), None))), TypeTree.Ident("Unit"), Some(Term.Block(Nil, Term.Inlined(Some(TypeTree.Ident("Macros$")), Nil, Term.Select(Term.Apply(Term.Apply(Term.TypeApply(Term.Ident("impl"), List(TypeTree.Synthetic())), List(Term.Apply(Term.TypeApply(Term.Ident("apply"), List(TypeTree.Synthetic())), List(Term.Inlined(None, Nil, Term.Block(List(DefDef("foo", Nil, Nil, TypeTree.Synthetic(), Some(Term.Block(List(DefDef("bar", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(1)))), ValDef("bar2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(2))))), Term.Typed(Term.Ident("bar"), TypeTree.Synthetic())))), ValDef("foo2", TypeTree.Synthetic(), Some(Term.Block(List(DefDef("baz", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(3)))), ValDef("baz2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(4))))), Term.Typed(Term.Ident("baz"), TypeTree.Synthetic())))), ClassDef("A", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(TypeDef("B", TypeTree.Ident("Int")), DefDef("b", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(5)))), ValDef("b2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(6))))))), Term.Literal(Constant.Unit()))))))), List(Term.Ident("macroContext"))), "unary_~", Some(Signature(Nil, java.lang.Object))))))) bar DefDef("foo", Nil, Nil, TypeTree.Synthetic(), Some(Term.Block(List(DefDef("bar", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(1)))), ValDef("bar2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(2))))), Term.Typed(Term.Ident("bar"), TypeTree.Synthetic())))) @@ -8,7 +8,7 @@ bar2 DefDef("foo", Nil, Nil, TypeTree.Synthetic(), Some(Term.Block(List(DefDef("bar", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(1)))), ValDef("bar2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(2))))), Term.Typed(Term.Ident("bar"), TypeTree.Synthetic())))) foo2 -DefDef("main", Nil, List(List(ValDef("args", TypeTree.Applied(TypeTree.Ident("Array"), List(TypeTree.Ident("String"))), None))), TypeTree.Ident("Unit"), Some(Term.Block(Nil, Term.Apply(Term.TypeApply(Term.Ident("printOwners"), List(TypeTree.Synthetic())), List(Term.Block(List(DefDef("foo", Nil, Nil, TypeTree.Synthetic(), Some(Term.Block(List(DefDef("bar", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(1)))), ValDef("bar2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(2))))), Term.Typed(Term.Ident("bar"), TypeTree.Synthetic())))), ValDef("foo2", TypeTree.Synthetic(), Some(Term.Block(List(DefDef("baz", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(3)))), ValDef("baz2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(4))))), Term.Typed(Term.Ident("baz"), TypeTree.Synthetic())))), ClassDef("A", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(TypeDef("B", TypeTree.Ident("Int")), DefDef("b", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(5)))), ValDef("b2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(6))))))), Term.Literal(Constant.Unit()))))))) +DefDef("main", Nil, List(List(ValDef("args", TypeTree.Applied(TypeTree.Ident("Array"), List(TypeTree.Ident("String"))), None))), TypeTree.Ident("Unit"), Some(Term.Block(Nil, Term.Inlined(Some(TypeTree.Ident("Macros$")), Nil, Term.Select(Term.Apply(Term.Apply(Term.TypeApply(Term.Ident("impl"), List(TypeTree.Synthetic())), List(Term.Apply(Term.TypeApply(Term.Ident("apply"), List(TypeTree.Synthetic())), List(Term.Inlined(None, Nil, Term.Block(List(DefDef("foo", Nil, Nil, TypeTree.Synthetic(), Some(Term.Block(List(DefDef("bar", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(1)))), ValDef("bar2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(2))))), Term.Typed(Term.Ident("bar"), TypeTree.Synthetic())))), ValDef("foo2", TypeTree.Synthetic(), Some(Term.Block(List(DefDef("baz", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(3)))), ValDef("baz2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(4))))), Term.Typed(Term.Ident("baz"), TypeTree.Synthetic())))), ClassDef("A", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(TypeDef("B", TypeTree.Ident("Int")), DefDef("b", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(5)))), ValDef("b2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(6))))))), Term.Literal(Constant.Unit()))))))), List(Term.Ident("macroContext"))), "unary_~", Some(Signature(Nil, java.lang.Object))))))) baz ValDef("foo2", TypeTree.Synthetic(), Some(Term.Block(List(DefDef("baz", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(3)))), ValDef("baz2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(4))))), Term.Typed(Term.Ident("baz"), TypeTree.Synthetic())))) diff --git a/tests/run-with-compiler/i3876-d.check b/tests/run-with-compiler/i3876-d.check index de27d152d558..746b7f8778a7 100644 --- a/tests/run-with-compiler/i3876-d.check +++ b/tests/run-with-compiler/i3876-d.check @@ -1,5 +1,5 @@ 6 { val x$1: scala.Int = 3 - Test.inlineLambda.apply(x$1) + x$1.+(x$1) } From 70a5209b6b5c9af324cc212bf9cb045626573dad Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 4 Nov 2018 15:19:15 +0100 Subject: [PATCH 2/6] Support <: T syntax for inlined methods. - add new syntax - an inline method with an explicit `: T` result type section has its rhs upcasted to its return type. It was an oversight that this was not done before. --- .../src/dotty/tools/dotc/ast/Desugar.scala | 27 ++++++++++++++++--- .../dotty/tools/dotc/parsing/Parsers.scala | 10 +++++-- .../dotty/tools/dotc/transform/Staging.scala | 1 + docs/docs/internals/syntax.md | 2 +- tests/neg/specializing-inline.scala | 14 ++++++++++ 5 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 tests/neg/specializing-inline.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 419e1b11b76e..2f937946cc71 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -157,19 +157,31 @@ object desugar { ValDef(epname, tpt, EmptyTree).withFlags(paramFlags | Implicit) } - /** Expand context bounds to evidence params. E.g., + /** 1. Expand context bounds to evidence params. E.g., * * def f[T >: L <: H : B](params) * ==> * def f[T >: L <: H](params)(implicit evidence$0: B[T]) * - * Expand default arguments to default getters. E.g, + * 2. Expand default arguments to default getters. E.g, * * def f[T: B](x: Int = 1)(y: String = x + "m") = ... * ==> * def f[T](x: Int)(y: String)(implicit evidence$0: B[T]) = ... * def f$default$1[T] = 1 * def f$default$2[T](x: Int) = x + "m" + * + * 3. Convert <: T to : T in specializing inline methods. E.g. + * + * inline def f(x: Boolean) <: Any = if (x) 1 else "" + * ==> + * inline def f(x: Boolean): Any = if (x) 1 else "" + * + * 4. Upcast non-specializing inline methods. E.g. + * + * inline def f(x: Boolean): Any = if (x) 1 else "" + * ==> + * inline def f(x: Boolean): Any = (if (x) 1 else ""): Any */ private def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false)(implicit ctx: Context): Tree = { val DefDef(name, tparams, vparamss, tpt, rhs) = meth @@ -188,7 +200,16 @@ object desugar { cpy.TypeDef(tparam)(rhs = desugarContextBounds(tparam.rhs)) } - val meth1 = addEvidenceParams(cpy.DefDef(meth)(tparams = tparams1), epbuf.toList) + var meth1 = addEvidenceParams(cpy.DefDef(meth)(tparams = tparams1), epbuf.toList) + + if (meth1.mods.is(Inline)) + meth1.tpt match { + case TypeBoundsTree(_, tpt1) => + meth1 = cpy.DefDef(meth1)(tpt = tpt1) + case tpt if !tpt.isEmpty && !meth1.rhs.isEmpty => + meth1 = cpy.DefDef(meth1)(rhs = Typed(meth1.rhs, tpt)) + case _ => + } /** The longest prefix of parameter lists in vparamss whose total length does not exceed `n` */ def takeUpTo(vparamss: List[List[ValDef]], n: Int): List[List[ValDef]] = vparamss match { diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 2588b9c44691..e1fa29da0d07 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2166,7 +2166,7 @@ object Parsers { } } - /** DefDef ::= DefSig (`:' Type [`=' Expr] | "=" Expr) + /** DefDef ::= DefSig [(‘:’ | ‘<:’) Type] ‘=’ Expr * | this ParamClause ParamClauses `=' ConstrExpr * DefDcl ::= DefSig `:' Type * DefSig ::= id [DefTypeParamClause] ParamClauses @@ -2195,7 +2195,13 @@ object Parsers { val name = ident() val tparams = typeParamClauseOpt(ParamOwner.Def) val vparamss = paramClauses(name) - var tpt = fromWithinReturnType(typedOpt()) + var tpt = fromWithinReturnType { + if (in.token == SUBTYPE && mods.is(Inline)) { + in.nextToken() + TypeBoundsTree(EmptyTree, toplevelTyp()) + } + else typedOpt() + } if (in.isScala2Mode) newLineOptWhenFollowedBy(LBRACE) val rhs = if (in.token == EQUALS) { diff --git a/compiler/src/dotty/tools/dotc/transform/Staging.scala b/compiler/src/dotty/tools/dotc/transform/Staging.scala index 90a727e0eec8..f2255d53179c 100644 --- a/compiler/src/dotty/tools/dotc/transform/Staging.scala +++ b/compiler/src/dotty/tools/dotc/transform/Staging.scala @@ -628,6 +628,7 @@ class Staging extends MacroTransformWithImplicits { case Select(qual, _) if tree.symbol.isSplice && Splicer.canBeSpliced(qual) => Some(qual) case Block(List(stat), Literal(Constant(()))) => unapply(stat) case Block(Nil, expr) => unapply(expr) + case Typed(expr, _) => unapply(expr) case _ => None } } diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index 4145825cd73e..ef37c9214677 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -329,7 +329,7 @@ Def ::= ‘val’ PatDef PatDef ::= Pattern2 {‘,’ Pattern2} [‘:’ Type] ‘=’ Expr PatDef(_, pats, tpe?, expr) VarDef ::= PatDef | ids ‘:’ Type ‘=’ ‘_’ -DefDef ::= DefSig [‘:’ Type] ‘=’ Expr DefDef(_, name, tparams, vparamss, tpe, expr) +DefDef ::= DefSig [(‘:’ | ‘<:’) Type] ‘=’ Expr DefDef(_, name, tparams, vparamss, tpe, expr) | DefSig [nl] ‘{’ Block ‘}’ DefDef(_, name, tparams, vparamss, tpe, Block) | ‘this’ DefParamClause DefParamClauses DefDef(_, , Nil, vparamss, EmptyTree, expr | Block) (‘=’ ConstrExpr | [nl] ConstrBlock) diff --git a/tests/neg/specializing-inline.scala b/tests/neg/specializing-inline.scala new file mode 100644 index 000000000000..450c24708b4d --- /dev/null +++ b/tests/neg/specializing-inline.scala @@ -0,0 +1,14 @@ +object Test { + + inline def h(x: Boolean) = if (x) 1 else "" + val z = h(true) + val zc: Int = z + + inline def g <: Any = 1 + val y = g + val yc: Int = y // OK + + inline def f: Any = 1 + val x = f + val xc: Int = x // error +} \ No newline at end of file From 571d1ba0a7cf97e3534e911c4555aa153bd599a4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 4 Nov 2018 18:49:06 +0100 Subject: [PATCH 3/6] Print a space between a symbolic operator and a colon. This affects both RefinedPrinter and ShowSougrceCode. Another example of the tax we pay for maintaining both. It required Chars to be moved to scala.tasty. --- .../src/dotty/tools/dotc/core/NameOps.scala | 2 +- .../src/dotty/tools/dotc/core/Names.scala | 2 +- .../tools/dotc/parsing/CharArrayReader.scala | 2 +- .../tools/dotc/parsing/JavaScanners.scala | 2 +- .../dotty/tools/dotc/parsing/Scanners.scala | 2 +- .../dotty/tools/dotc/parsing/package.scala | 2 +- .../dotc/parsing/xml/MarkupParserCommon.scala | 2 +- .../dotc/parsing/xml/MarkupParsers.scala | 2 +- .../tools/dotc/parsing/xml/Utility.scala | 2 +- .../tools/dotc/printing/RefinedPrinter.scala | 7 +- .../dotc/reporting/MessageRendering.scala | 2 +- .../tools/dotc/transform/TreeChecker.scala | 2 +- .../tools/dotc/util/CommentParsing.scala | 2 +- .../tools/dotc/util/NameTransformer.scala | 6 +- .../dotty/tools/dotc/util/SourceFile.scala | 2 +- .../src/scala/tasty}/util/Chars.scala | 7 +- .../src/scala/tasty/util/ShowSourceCode.scala | 2 +- tests/pos/test.sc | 87 +++++++++++++++++++ 18 files changed, 111 insertions(+), 24 deletions(-) rename {compiler/src/dotty/tools/dotc => library/src/scala/tasty}/util/Chars.scala (96%) create mode 100644 tests/pos/test.sc diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index b85c57dc8409..9aab83206501 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -4,7 +4,7 @@ package core import java.security.MessageDigest import scala.io.Codec import Names._, StdNames._, Contexts._, Symbols._, Flags._, NameKinds._, Types._ -import util.Chars +import scala.tasty.util.Chars import Chars.isOperatorPart import Definitions._ diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 83d1a564edbf..8b1975f6d1fd 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -7,7 +7,7 @@ import util.NameTransformer import printing.{Showable, Texts, Printer} import Texts.Text import StdNames.str -import util.Chars.isIdentifierStart +import scala.tasty.util.Chars.isIdentifierStart import collection.immutable import config.Config import java.util.HashMap diff --git a/compiler/src/dotty/tools/dotc/parsing/CharArrayReader.scala b/compiler/src/dotty/tools/dotc/parsing/CharArrayReader.scala index 3eef265e5a2a..1d07b99ea07e 100644 --- a/compiler/src/dotty/tools/dotc/parsing/CharArrayReader.scala +++ b/compiler/src/dotty/tools/dotc/parsing/CharArrayReader.scala @@ -2,7 +2,7 @@ package dotty.tools package dotc package parsing -import util.Chars._ +import scala.tasty.util.Chars._ abstract class CharArrayReader { self => diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaScanners.scala b/compiler/src/dotty/tools/dotc/parsing/JavaScanners.scala index 10435003838d..34c8120921f3 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaScanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaScanners.scala @@ -7,7 +7,7 @@ import Scanners._ import util.SourceFile import JavaTokens._ import scala.annotation.{ switch, tailrec } -import util.Chars._ +import scala.tasty.util.Chars._ object JavaScanners { diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 731a280f0407..adb9eb258e6f 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -6,7 +6,7 @@ import core.Names._, core.Contexts._, core.Decorators._, util.Positions._ import core.StdNames._, core.Comments._ import util.SourceFile import java.lang.Character.isDigit -import util.Chars._ +import scala.tasty.util.Chars._ import util.NameTransformer.avoidIllegalChars import Tokens._ import scala.annotation.{ switch, tailrec } diff --git a/compiler/src/dotty/tools/dotc/parsing/package.scala b/compiler/src/dotty/tools/dotc/parsing/package.scala index 5a0bde20bd0f..4871d1b893c1 100644 --- a/compiler/src/dotty/tools/dotc/parsing/package.scala +++ b/compiler/src/dotty/tools/dotc/parsing/package.scala @@ -1,6 +1,6 @@ package dotty.tools.dotc -import util.Chars._ +import scala.tasty.util.Chars._ import core.Names.Name import core.StdNames.nme import core.NameOps._ diff --git a/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParserCommon.scala b/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParserCommon.scala index 5d0961206d4b..a7a22d1cee34 100644 --- a/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParserCommon.scala +++ b/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParserCommon.scala @@ -10,7 +10,7 @@ package parsing package xml import Utility._ -import util.Chars.SU +import scala.tasty.util.Chars.SU diff --git a/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala b/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala index 5f4e8c1096d9..0f0a0d36bf53 100644 --- a/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala @@ -6,7 +6,7 @@ package xml import scala.collection.mutable import mutable.{ Buffer, ArrayBuffer, ListBuffer } import scala.util.control.ControlThrowable -import util.Chars.SU +import scala.tasty.util.Chars.SU import Parsers._ import util.Positions._ import core._ diff --git a/compiler/src/dotty/tools/dotc/parsing/xml/Utility.scala b/compiler/src/dotty/tools/dotc/parsing/xml/Utility.scala index 50cee13c9e1a..ad2a5fe54758 100644 --- a/compiler/src/dotty/tools/dotc/parsing/xml/Utility.scala +++ b/compiler/src/dotty/tools/dotc/parsing/xml/Utility.scala @@ -12,7 +12,7 @@ import scala.collection.mutable * @author Burak Emir */ object Utility { - import util.Chars.SU + import scala.tasty.util.Chars.SU private val unescMap = Map( "lt" -> '<', diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index afd2b15f794e..6b81f57dceed 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -19,6 +19,7 @@ import typer.ProtoTypes._ import Trees._ import TypeApplications._ import Decorators._ +import scala.tasty.util.Chars.isOperatorPart import transform.TypeUtils._ import language.implicitConversions @@ -345,7 +346,11 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } } case Typed(expr, tpt) => - changePrec(InfixPrec) { toText(expr) ~ ": " ~ toText(tpt) } + changePrec(InfixPrec) { + val exprText = toText(expr) + val line = exprText.lastLine + val colon = if (!line.isEmpty && isOperatorPart(line.last)) " :" else ":" + exprText ~ colon ~ toText(tpt) } case NamedArg(name, arg) => toText(name) ~ " = " ~ toText(arg) case Assign(lhs, rhs) => diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index 85db42421550..426b1f269c78 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -9,7 +9,7 @@ import printing.SyntaxHighlighting import diagnostic.{ErrorMessageID, Message, MessageContainer} import diagnostic.messages._ import util.SourcePosition -import util.Chars.{ LF, CR, FF, SU } +import scala.tasty.util.Chars.{ LF, CR, FF, SU } import scala.annotation.switch import scala.collection.mutable diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 39f36bc4007f..6ad359bc7d61 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -18,7 +18,7 @@ import typer.ErrorReporting._ import reporting.ThrowingReporter import ast.Trees._ import ast.{tpd, untpd} -import util.Chars._ +import scala.tasty.util.Chars._ import collection.mutable import ProtoTypes._ diff --git a/compiler/src/dotty/tools/dotc/util/CommentParsing.scala b/compiler/src/dotty/tools/dotc/util/CommentParsing.scala index 9e97a724ba75..2132cdcde73b 100644 --- a/compiler/src/dotty/tools/dotc/util/CommentParsing.scala +++ b/compiler/src/dotty/tools/dotc/util/CommentParsing.scala @@ -13,7 +13,7 @@ package dotty.tools.dotc.util * handled by dottydoc. */ object CommentParsing { - import Chars._ + import scala.tasty.util.Chars._ /** Returns index of string `str` following `start` skipping longest * sequence of whitespace characters characters (but no newlines) diff --git a/compiler/src/dotty/tools/dotc/util/NameTransformer.scala b/compiler/src/dotty/tools/dotc/util/NameTransformer.scala index e75d91c64b35..d489c1ed0e42 100644 --- a/compiler/src/dotty/tools/dotc/util/NameTransformer.scala +++ b/compiler/src/dotty/tools/dotc/util/NameTransformer.scala @@ -4,7 +4,7 @@ package util import core.Names._ import collection.mutable -import util.Chars.isValidJVMMethodChar +import scala.tasty.util.Chars import scala.annotation.internal.sharable @@ -47,11 +47,11 @@ object NameTransformer { */ def avoidIllegalChars(name: SimpleName): SimpleName = { var i = name.length - 1 - while (i >= 0 && isValidJVMMethodChar(name(i))) i -= 1 + while (i >= 0 && Chars.isValidJVMMethodChar(name(i))) i -= 1 if (i >= 0) termName( name.toString.flatMap(ch => - if (isValidJVMMethodChar(ch)) ch.toString else "$u%04X".format(ch.toInt))) + if (Chars.isValidJVMMethodChar(ch)) ch.toString else "$u%04X".format(ch.toInt))) else name } diff --git a/compiler/src/dotty/tools/dotc/util/SourceFile.scala b/compiler/src/dotty/tools/dotc/util/SourceFile.scala index 3c0b234a17cc..d200fae54df3 100644 --- a/compiler/src/dotty/tools/dotc/util/SourceFile.scala +++ b/compiler/src/dotty/tools/dotc/util/SourceFile.scala @@ -6,7 +6,7 @@ import scala.collection.mutable.ArrayBuffer import dotty.tools.io._ import java.util.regex.Pattern import java.io.IOException -import Chars._ +import scala.tasty.util.Chars._ import Positions._ import scala.io.Codec import scala.annotation.internal.sharable diff --git a/compiler/src/dotty/tools/dotc/util/Chars.scala b/library/src/scala/tasty/util/Chars.scala similarity index 96% rename from compiler/src/dotty/tools/dotc/util/Chars.scala rename to library/src/scala/tasty/util/Chars.scala index 9620fa2b8859..433b94e868a7 100644 --- a/compiler/src/dotty/tools/dotc/util/Chars.scala +++ b/library/src/scala/tasty/util/Chars.scala @@ -1,9 +1,4 @@ -/* NSC -- new Scala compiler - * Copyright 2006-2012 LAMP/EPFL - * @author Martin Odersky - */ -package dotty.tools.dotc -package util +package scala.tasty.util import scala.annotation.switch import java.lang.{Character => JCharacter} diff --git a/library/src/scala/tasty/util/ShowSourceCode.scala b/library/src/scala/tasty/util/ShowSourceCode.scala index c7f3c9a1b01e..2a47b063e9f0 100644 --- a/library/src/scala/tasty/util/ShowSourceCode.scala +++ b/library/src/scala/tasty/util/ShowSourceCode.scala @@ -354,7 +354,7 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty case _ => inParens { printTree(term) - this += ": " + this += (if (Chars.isOperatorPart(sb.last)) " : " else ": ") def printTypeOrAnnots(tpe: Type): Unit = tpe match { case Type.AnnotatedType(tp, annot) if tp == term.tpe => printAnnotation(annot) diff --git a/tests/pos/test.sc b/tests/pos/test.sc new file mode 100644 index 000000000000..8cad24ab31ca --- /dev/null +++ b/tests/pos/test.sc @@ -0,0 +1,87 @@ +val x = 22 + +val y = x * 2 +def square(x: Double) = x * x +square(33) + +class Bar +type L = scala.List + +def zip[T, U](xs: List[T], ys: List[U]) = { + val (ps, _) = xs.foldLeft((Nil: List[(T, U)], ys)) { + (acc, x) => + val (ps, ys) = acc + ys match { + case Nil => acc + case y :: ys => ((x, y) :: ps, ys) + } + } + ps.reverse + } +zip(List(1, 2, 3, 4), List("a", "b", "c")) + +def zips(xss: List[List[Int]]): List[List[Int]] = { + if (xss.forall(_.nonEmpty)) + xss.map(_.head) :: zips(xss.map(_.tail)) + else Nil +} + +zips( + List( + List(1, 2, 3), + List(11, 22), + List(111, 222, 333, 444) + )) + +abstract class A { + def foo: Any +} +abstract class B extends A { + def foo: Int +} +abstract class C extends A { + def foo: Int +} +def f: A | B = ??? +def g = f.foo + + +val xx = 22 + +trait T { + def apply(x: Int): Unit = () +} +class CC extends T { + override def apply(x: Int) = super.apply(1) +} +object o { + def apply(): String = "" +} +val s: String = o() + +Double.NaN.equals(Double.NaN) + +trait Status +case object A extends Status +case object B extends Status + +if (true) A else B + +case class Wrapper(i: Int) + +trait Functor[F[_]] { + def map[A, B](x: F[A], f: A => B): F[B] +} + +class Deriver[F[_]] { + def foldLeft[A, B](result: A, value: B): A +} + +trait Eq[A] { + def equals(x: A, y: A): Boolean +} + +trait DC { type TT } + +def m(x: DC): x.TT = ??? +val meta = m \ No newline at end of file From 08f37002236bf93d76bf42192ae0cb5b772dff40 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 4 Nov 2018 20:38:05 +0100 Subject: [PATCH 4/6] Adapt class parameters in inlined code --- compiler/src/dotty/tools/dotc/typer/Inliner.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 933e7c10c81f..ef61b24a6fb5 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -301,13 +301,16 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { private def registerType(tpe: Type): Unit = tpe match { case tpe: ThisType if !canElideThis(tpe) && !thisProxy.contains(tpe.cls) => val proxyName = s"${tpe.cls.name}_this".toTermName + def adaptToPrefix(tp: Type) = tp.asSeenFrom(inlineCallPrefix.tpe, inlinedMethod.owner) val proxyType = inlineCallPrefix.tpe.dealias.tryNormalize match { case typeMatchResult if typeMatchResult.exists => typeMatchResult - case _ => tpe.asSeenFrom(inlineCallPrefix.tpe, inlinedMethod.owner).widenIfUnstable + case _ => adaptToPrefix(tpe).widenIfUnstable } thisProxy(tpe.cls) = newSym(proxyName, InlineProxy, proxyType).termRef if (!tpe.cls.isStaticOwner) registerType(inlinedMethod.owner.thisType) // make sure we have a base from which to outer-select + for (param <- tpe.cls.typeParams) + paramProxy(param.typeRef) = adaptToPrefix(param.typeRef) case tpe: NamedType if tpe.symbol.is(Param) && tpe.symbol.owner == inlinedMethod && !paramProxy.contains(tpe) => paramProxy(tpe) = paramBinding(tpe.name) From 19102cf3c1b86b40f73d7e1eaf252de3a029d13f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 4 Nov 2018 20:39:09 +0100 Subject: [PATCH 5/6] Fix tests These tests all failed because we now put some inlined code in a Typed(...) node. --- compiler/test/dotc/pos-decompilation.blacklist | 5 +++++ compiler/test/dotc/pos-from-tasty.blacklist | 7 ++++++- .../tools/backend/jvm/InlineBytecodeTests.scala | 14 +++++++------- tests/disabled/pos/inline-named-typeargs.scala | 5 +++++ tests/pos/i4006.scala | 2 +- tests/pos/inline-named-typeargs.scala | 5 ++--- tests/pos/simpleInline.decompiled | 6 +++--- .../Yretain-trees/tasty-extractors-owners.check | 4 ++-- tests/run-separate-compilation/i5119.check | 2 +- .../xml-interpolation-2/XmlQuote_1.scala | 7 ++++++- tests/run-with-compiler/i3876-d.scala | 2 +- 11 files changed, 39 insertions(+), 20 deletions(-) create mode 100644 tests/disabled/pos/inline-named-typeargs.scala diff --git a/compiler/test/dotc/pos-decompilation.blacklist b/compiler/test/dotc/pos-decompilation.blacklist index 2efb126acde1..7167432f404b 100644 --- a/compiler/test/dotc/pos-decompilation.blacklist +++ b/compiler/test/dotc/pos-decompilation.blacklist @@ -7,3 +7,8 @@ i2888.scala tcpoly_overloaded.scala tcpoly_boundedmonad.scala tcpoly_checkkinds_mix.scala + +# Did not survive addition of type ascriptions +i3050.scala +i4006b.scala +i4006c.scala diff --git a/compiler/test/dotc/pos-from-tasty.blacklist b/compiler/test/dotc/pos-from-tasty.blacklist index a48abcd017a0..109261d031b6 100644 --- a/compiler/test/dotc/pos-from-tasty.blacklist +++ b/compiler/test/dotc/pos-from-tasty.blacklist @@ -17,4 +17,9 @@ repeatedArgs213.scala default-super.scala # Need to implement printing of match types -matchtype.scala \ No newline at end of file +matchtype.scala + +# Did not survive addition of type ascriptions in decompiled tests +i3050.scala +i4006b.scala +i4006c.scala diff --git a/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala b/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala index d871d10ae773..43dec059f9bd 100644 --- a/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala +++ b/compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala @@ -44,7 +44,7 @@ class InlineBytecodeTests extends DottyBytecodeTest { @Test def i4947 = { val source = """class Foo { - | inline def track[T](f: => T): T = { + | inline def track[T](f: => T) <: T = { | foo("tracking") // line 3 | f // line 4 | } @@ -103,11 +103,11 @@ class InlineBytecodeTests extends DottyBytecodeTest { @Test def i4947b = { val source = """class Foo { - | inline def track2[T](f: => T): T = { + | inline def track2[T](f: => T) <: T = { | foo("tracking2") // line 3 | f // line 4 | } - | inline def track[T](f: => T): T = { + | inline def track[T](f: => T) <: T = { | foo("tracking") // line 7 | track2 { // line 8 | f // line 9 @@ -163,11 +163,11 @@ class InlineBytecodeTests extends DottyBytecodeTest { @Test def i4947c = { val source = """class Foo { - | inline def track2[T](f: => T): T = { + | inline def track2[T](f: => T) <: T = { | foo("tracking2") // line 3 | f // line 4 | } - | inline def track[T](f: => T): T = { + | inline def track[T](f: => T) <: T = { | track2 { // line 7 | foo("fgh") // line 8 | f // line 9 @@ -223,11 +223,11 @@ class InlineBytecodeTests extends DottyBytecodeTest { @Test def i4947d = { val source = """class Foo { - | inline def track2[T](f: => T): T = { + | inline def track2[T](f: => T) <: T = { | foo("tracking2") // line 3 | f // line 4 | } - | inline def track[T](f: => T): T = { + | inline def track[T](f: => T) <: T = { | track2 { // line 7 | track2 { // line 8 | f // line 9 diff --git a/tests/disabled/pos/inline-named-typeargs.scala b/tests/disabled/pos/inline-named-typeargs.scala new file mode 100644 index 000000000000..9d2c5b3f4af9 --- /dev/null +++ b/tests/disabled/pos/inline-named-typeargs.scala @@ -0,0 +1,5 @@ +object t1 { + inline def construct[Elem, Coll[_]](xs: List[Elem]): Coll[Elem] = ??? + + val xs3 = construct[Coll = List](List(1, 2, 3)) +} diff --git a/tests/pos/i4006.scala b/tests/pos/i4006.scala index ef86dbb052f1..328020381f37 100644 --- a/tests/pos/i4006.scala +++ b/tests/pos/i4006.scala @@ -1,4 +1,4 @@ class Foo { - inline def foo: Int = try { 1 } finally println("Hello") + inline def foo <: Int = try { 1 } finally println("Hello") foo } diff --git a/tests/pos/inline-named-typeargs.scala b/tests/pos/inline-named-typeargs.scala index 9d2c5b3f4af9..16ec48610b8f 100644 --- a/tests/pos/inline-named-typeargs.scala +++ b/tests/pos/inline-named-typeargs.scala @@ -1,5 +1,4 @@ +// Working version of inline-named-typedargs, the original is currently disabled object t1 { - inline def construct[Elem, Coll[_]](xs: List[Elem]): Coll[Elem] = ??? - - val xs3 = construct[Coll = List](List(1, 2, 3)) + inline def construct[Elem, Coll[_]](xs: List[Elem]) <: Coll[Elem] = ??? } diff --git a/tests/pos/simpleInline.decompiled b/tests/pos/simpleInline.decompiled index 492a0da6e777..a75db7d705d3 100644 --- a/tests/pos/simpleInline.decompiled +++ b/tests/pos/simpleInline.decompiled @@ -1,7 +1,7 @@ /** Decompiled from out/posTestFromTasty/pos/simpleInline/Foo.class */ class Foo() { - inline def foo: scala.Int = 9 + inline def foo: scala.Int = (9: scala.Int) def bar: scala.Int = { // inlined - 9 + (9: scala.Int) } -} +} \ No newline at end of file diff --git a/tests/run-custom-args/Yretain-trees/tasty-extractors-owners.check b/tests/run-custom-args/Yretain-trees/tasty-extractors-owners.check index d541fcc56321..5fddbc212724 100644 --- a/tests/run-custom-args/Yretain-trees/tasty-extractors-owners.check +++ b/tests/run-custom-args/Yretain-trees/tasty-extractors-owners.check @@ -1,5 +1,5 @@ foo -DefDef("main", Nil, List(List(ValDef("args", TypeTree.Applied(TypeTree.Ident("Array"), List(TypeTree.Ident("String"))), None))), TypeTree.Ident("Unit"), Some(Term.Block(Nil, Term.Inlined(Some(TypeTree.Ident("Macros$")), Nil, Term.Select(Term.Apply(Term.Apply(Term.TypeApply(Term.Ident("impl"), List(TypeTree.Synthetic())), List(Term.Apply(Term.TypeApply(Term.Ident("apply"), List(TypeTree.Synthetic())), List(Term.Inlined(None, Nil, Term.Block(List(DefDef("foo", Nil, Nil, TypeTree.Synthetic(), Some(Term.Block(List(DefDef("bar", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(1)))), ValDef("bar2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(2))))), Term.Typed(Term.Ident("bar"), TypeTree.Synthetic())))), ValDef("foo2", TypeTree.Synthetic(), Some(Term.Block(List(DefDef("baz", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(3)))), ValDef("baz2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(4))))), Term.Typed(Term.Ident("baz"), TypeTree.Synthetic())))), ClassDef("A", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(TypeDef("B", TypeTree.Ident("Int")), DefDef("b", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(5)))), ValDef("b2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(6))))))), Term.Literal(Constant.Unit()))))))), List(Term.Ident("macroContext"))), "unary_~", Some(Signature(Nil, java.lang.Object))))))) +DefDef("main", Nil, List(List(ValDef("args", TypeTree.Applied(TypeTree.Ident("Array"), List(TypeTree.Ident("String"))), None))), TypeTree.Ident("Unit"), Some(Term.Block(Nil, Term.Inlined(Some(TypeTree.Ident("Macros$")), Nil, Term.Typed(Term.Select(Term.Apply(Term.Apply(Term.TypeApply(Term.Ident("impl"), List(TypeTree.Synthetic())), List(Term.Apply(Term.TypeApply(Term.Ident("apply"), List(TypeTree.Synthetic())), List(Term.Inlined(None, Nil, Term.Block(List(DefDef("foo", Nil, Nil, TypeTree.Synthetic(), Some(Term.Block(List(DefDef("bar", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(1)))), ValDef("bar2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(2))))), Term.Typed(Term.Ident("bar"), TypeTree.Synthetic())))), ValDef("foo2", TypeTree.Synthetic(), Some(Term.Block(List(DefDef("baz", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(3)))), ValDef("baz2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(4))))), Term.Typed(Term.Ident("baz"), TypeTree.Synthetic())))), ClassDef("A", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(TypeDef("B", TypeTree.Ident("Int")), DefDef("b", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(5)))), ValDef("b2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(6))))))), Term.Literal(Constant.Unit()))))))), List(Term.Ident("macroContext"))), "unary_~", Some(Signature(Nil, java.lang.Object))), TypeTree.Ident("Unit")))))) bar DefDef("foo", Nil, Nil, TypeTree.Synthetic(), Some(Term.Block(List(DefDef("bar", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(1)))), ValDef("bar2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(2))))), Term.Typed(Term.Ident("bar"), TypeTree.Synthetic())))) @@ -8,7 +8,7 @@ bar2 DefDef("foo", Nil, Nil, TypeTree.Synthetic(), Some(Term.Block(List(DefDef("bar", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(1)))), ValDef("bar2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(2))))), Term.Typed(Term.Ident("bar"), TypeTree.Synthetic())))) foo2 -DefDef("main", Nil, List(List(ValDef("args", TypeTree.Applied(TypeTree.Ident("Array"), List(TypeTree.Ident("String"))), None))), TypeTree.Ident("Unit"), Some(Term.Block(Nil, Term.Inlined(Some(TypeTree.Ident("Macros$")), Nil, Term.Select(Term.Apply(Term.Apply(Term.TypeApply(Term.Ident("impl"), List(TypeTree.Synthetic())), List(Term.Apply(Term.TypeApply(Term.Ident("apply"), List(TypeTree.Synthetic())), List(Term.Inlined(None, Nil, Term.Block(List(DefDef("foo", Nil, Nil, TypeTree.Synthetic(), Some(Term.Block(List(DefDef("bar", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(1)))), ValDef("bar2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(2))))), Term.Typed(Term.Ident("bar"), TypeTree.Synthetic())))), ValDef("foo2", TypeTree.Synthetic(), Some(Term.Block(List(DefDef("baz", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(3)))), ValDef("baz2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(4))))), Term.Typed(Term.Ident("baz"), TypeTree.Synthetic())))), ClassDef("A", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(TypeDef("B", TypeTree.Ident("Int")), DefDef("b", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(5)))), ValDef("b2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(6))))))), Term.Literal(Constant.Unit()))))))), List(Term.Ident("macroContext"))), "unary_~", Some(Signature(Nil, java.lang.Object))))))) +DefDef("main", Nil, List(List(ValDef("args", TypeTree.Applied(TypeTree.Ident("Array"), List(TypeTree.Ident("String"))), None))), TypeTree.Ident("Unit"), Some(Term.Block(Nil, Term.Inlined(Some(TypeTree.Ident("Macros$")), Nil, Term.Typed(Term.Select(Term.Apply(Term.Apply(Term.TypeApply(Term.Ident("impl"), List(TypeTree.Synthetic())), List(Term.Apply(Term.TypeApply(Term.Ident("apply"), List(TypeTree.Synthetic())), List(Term.Inlined(None, Nil, Term.Block(List(DefDef("foo", Nil, Nil, TypeTree.Synthetic(), Some(Term.Block(List(DefDef("bar", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(1)))), ValDef("bar2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(2))))), Term.Typed(Term.Ident("bar"), TypeTree.Synthetic())))), ValDef("foo2", TypeTree.Synthetic(), Some(Term.Block(List(DefDef("baz", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(3)))), ValDef("baz2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(4))))), Term.Typed(Term.Ident("baz"), TypeTree.Synthetic())))), ClassDef("A", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(TypeDef("B", TypeTree.Ident("Int")), DefDef("b", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(5)))), ValDef("b2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(6))))))), Term.Literal(Constant.Unit()))))))), List(Term.Ident("macroContext"))), "unary_~", Some(Signature(Nil, java.lang.Object))), TypeTree.Ident("Unit")))))) baz ValDef("foo2", TypeTree.Synthetic(), Some(Term.Block(List(DefDef("baz", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(3)))), ValDef("baz2", TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(4))))), Term.Typed(Term.Ident("baz"), TypeTree.Synthetic())))) diff --git a/tests/run-separate-compilation/i5119.check b/tests/run-separate-compilation/i5119.check index 9d4a29db156c..f77c20bc9266 100644 --- a/tests/run-separate-compilation/i5119.check +++ b/tests/run-separate-compilation/i5119.check @@ -1,2 +1,2 @@ -Term.Select(Term.Apply(Term.Select(Term.New(TypeTree.Ident("StringContextOps")), "", Some(Signature(List(scala.Function0), Macro$.StringContextOps))), List(Term.Apply(Term.Select(Term.Select(Term.Select(Term.Ident("_root_"), "scala", None), "StringContext", None), "apply", Some(Signature(List(scala.collection.Seq), scala.StringContext))), List(Term.Typed(Term.Repeated(List(Term.Literal(Constant.String("Hello World ")), Term.Literal(Constant.String("!")))), TypeTree.Synthetic()))))), "inline$sc", Some(Signature(Nil, scala.StringContext))) +Term.Select(Term.Typed(Term.Apply(Term.Select(Term.New(TypeTree.Ident("StringContextOps")), "", Some(Signature(List(scala.Function0), Macro$.StringContextOps))), List(Term.Apply(Term.Select(Term.Select(Term.Select(Term.Ident("_root_"), "scala", None), "StringContext", None), "apply", Some(Signature(List(scala.collection.Seq), scala.StringContext))), List(Term.Typed(Term.Repeated(List(Term.Literal(Constant.String("Hello World ")), Term.Literal(Constant.String("!")))), TypeTree.Synthetic()))))), TypeTree.Ident("StringContextOps")), "inline$sc", Some(Signature(Nil, scala.StringContext))) Term.Typed(Term.Repeated(List(Term.Literal(Constant.Int(1)))), TypeTree.Synthetic()) diff --git a/tests/run-separate-compilation/xml-interpolation-2/XmlQuote_1.scala b/tests/run-separate-compilation/xml-interpolation-2/XmlQuote_1.scala index f8e726acd1ff..6b7ca930b4ea 100644 --- a/tests/run-separate-compilation/xml-interpolation-2/XmlQuote_1.scala +++ b/tests/run-separate-compilation/xml-interpolation-2/XmlQuote_1.scala @@ -32,8 +32,13 @@ object XmlQuote { tree.symbol.fullName == "scala.StringContext$.apply" || tree.symbol.fullName == "scala.StringContext." + def stripTyped(t: Term) = t match { + case Typed(expr, _) => expr + case _ => t + } + // XmlQuote.SCOps(StringContext.apply([p0, ...]: String*) - val parts: List[String] = receiver.toTasty.underlying match { + val parts: List[String] = stripTyped(receiver.toTasty.underlying) match { case Apply(conv, List(ctx1)) if isSCOpsConversion(conv) => ctx1 match { case Apply(fun, List(Typed(Repeated(values), _))) if isStringContextApply(fun) => diff --git a/tests/run-with-compiler/i3876-d.scala b/tests/run-with-compiler/i3876-d.scala index 8da82245c99b..c3c2bec7a70a 100644 --- a/tests/run-with-compiler/i3876-d.scala +++ b/tests/run-with-compiler/i3876-d.scala @@ -13,5 +13,5 @@ object Test { println(f4(x).show) } - inline def inlineLambda: Int => Int = x => x + x + inline def inlineLambda <: Int => Int = x => x + x } \ No newline at end of file From 221d337c4dc9676afad2cf8496817874aae17ecb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 5 Nov 2018 11:18:36 +0100 Subject: [PATCH 6/6] Address review comment --- compiler/src/dotty/tools/dotc/Compiler.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index aeb063767e65..3bf3ea57d918 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -44,7 +44,7 @@ class Compiler { /** Phases dealing with TASTY tree pickling and unpickling */ protected def picklerPhases: List[List[Phase]] = List(new Pickler) :: // Generate TASTY info - List(new Staging) :: // Turn quoted trees into explicit run-time data structures + List(new Staging) :: // Expand macros and turn quoted trees into explicit run-time data structures Nil /** Phases dealing with the transformation from pickled trees to backend trees */