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..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) :: // Inline calls, expand macros and 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 */ 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/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/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/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/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/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/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/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..f2255d53179c 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)) } } @@ -638,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 } } @@ -676,20 +667,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/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/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 1432c5405cad..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) @@ -455,18 +458,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/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/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 ace498a34d3f..109261d031b6 100644 --- a/compiler/test/dotc/pos-from-tasty.blacklist +++ b/compiler/test/dotc/pos-from-tasty.blacklist @@ -19,5 +19,7 @@ default-super.scala # Need to implement printing of match types matchtype.scala -# Fails on CI (not locally) -inline-named-typeargs.scala +# Did not survive addition of type ascriptions in decompiled tests +i3050.scala +i4006b.scala +i4006c.scala 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/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/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/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/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/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/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 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/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 7fa25f3b3720..a75db7d705d3 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 -} + inline def foo: scala.Int = (9: scala.Int) + def bar: scala.Int = { // inlined + (9: scala.Int) + } +} \ No newline at end of file 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 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..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.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.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.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.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.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) } 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