Skip to content

Commit dd47092

Browse files
committed
Redefine semantics of inline parameters
See docs/docs/reference/metaprogramming/inline.md
1 parent 031e6f2 commit dd47092

File tree

67 files changed

+648
-516
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+648
-516
lines changed

compiler/src/dotty/tools/dotc/core/TypeErasure.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
533533
// but potentially re-introduced by ResolveSuper, when we add
534534
// forwarders to mixin methods.
535535
// See doc comment for ElimByName for speculation how we could improve this.
536-
else MethodType(Nil, Nil, eraseResult(sym.info.finalResultType))
536+
else MethodType(Nil, Nil, eraseResult(sym.info.finalResultType.underlyingIfRepeated(isJava)))
537537
case tp: PolyType =>
538538
eraseResult(tp.resultType) match {
539539
case rt: MethodType => rt

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3360,11 +3360,11 @@ object Types {
33603360
/** Produce method type from parameter symbols, with special mappings for repeated
33613361
* and inline parameters:
33623362
* - replace @repeated annotations on Seq or Array types by <repeated> types
3363-
* - add @inlineParam to inline call-by-value parameters
3363+
* - add @inlineParam to inline parameters
33643364
*/
33653365
def fromSymbols(params: List[Symbol], resultType: Type)(implicit ctx: Context): MethodType = {
33663366
def translateInline(tp: Type): Type = tp match {
3367-
case _: ExprType => tp
3367+
case ExprType(resType) => ExprType(AnnotatedType(resType, Annotation(defn.InlineParamAnnot)))
33683368
case _ => AnnotatedType(tp, Annotation(defn.InlineParamAnnot))
33693369
}
33703370
def paramInfo(param: Symbol) = {

compiler/src/dotty/tools/dotc/reporting/trace.scala

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,18 @@ object trace extends TraceSyntax {
2525
abstract class TraceSyntax {
2626
val isForced: Boolean
2727

28+
// FIXME Use this signature after reference compiler is updated
29+
// inline def onDebug[TD](inline question: String)(inline op: TD)(implicit ctx: Context): TD =
2830
inline def onDebug[TD](question: => String)(op: => TD)(implicit ctx: Context): TD =
2931
conditionally(ctx.settings.YdebugTrace.value, question, false)(op)
3032

33+
// FIXME Use this implementation after reference compiler is updated
34+
// inline def conditionally[TC](inline cond: Boolean, inline question: String, inline show: Boolean)(op: => TC)(implicit ctx: Context): TC =
35+
// inline if (isForced || Config.tracingEnabled) {
36+
// if (cond) apply[TC](question, Printers.default, show)(op)
37+
// else op
38+
// }
39+
// else op
3140
inline def conditionally[TC](cond: Boolean, question: => String, show: Boolean)(op: => TC)(implicit ctx: Context): TC =
3241
inline if (isForced || Config.tracingEnabled) {
3342
def op1 = op
@@ -36,6 +45,13 @@ abstract class TraceSyntax {
3645
}
3746
else op
3847

48+
// FIXME Use this implementation after reference compiler is updated
49+
// inline def apply[T](inline question: String, inline printer: Printers.Printer, inline showOp: Any => String)(op: => T)(implicit ctx: Context): T =
50+
// inline if (isForced || Config.tracingEnabled) {
51+
// if (!isForced && printer.eq(config.Printers.noPrinter)) op
52+
// else doTrace[T](question, printer, showOp)(op)
53+
// }
54+
// else op
3955
inline def apply[T](question: => String, printer: Printers.Printer, showOp: Any => String)(op: => T)(implicit ctx: Context): T =
4056
inline if (isForced || Config.tracingEnabled) {
4157
def op1 = op
@@ -44,6 +60,13 @@ abstract class TraceSyntax {
4460
}
4561
else op
4662

63+
// FIXME Use this implementation after reference compiler is updated
64+
// inline def apply[T](inline question: String, inline printer: Printers.Printer, inline show: Boolean)(op: => T)(implicit ctx: Context): T =
65+
// inline if (isForced || Config.tracingEnabled) {
66+
// if (!isForced && printer.eq(config.Printers.noPrinter)) op
67+
// else doTrace[T](question, printer, if (show) showShowable(_) else alwaysToString)(op)
68+
// }
69+
// else op
4770
inline def apply[T](question: => String, printer: Printers.Printer, show: Boolean)(op: => T)(implicit ctx: Context): T =
4871
inline if (isForced || Config.tracingEnabled) {
4972
def op1 = op
@@ -52,12 +75,18 @@ abstract class TraceSyntax {
5275
}
5376
else op
5477

78+
// FIXME Use this signature after reference compiler is updated
79+
// inline def apply[T](inline question: String, inline printer: Printers.Printer)(inline op: T)(implicit ctx: Context): T =
5580
inline def apply[T](question: => String, printer: Printers.Printer)(op: => T)(implicit ctx: Context): T =
5681
apply[T](question, printer, false)(op)
5782

83+
// FIXME Use this signature after reference compiler is updated
84+
// inline def apply[T](inline question: String, inline show: Boolean)(inline op: T)(implicit ctx: Context): T =
5885
inline def apply[T](question: => String, show: Boolean)(op: => T)(implicit ctx: Context): T =
5986
apply[T](question, Printers.default, show)(op)
6087

88+
// FIXME Use this signature after reference compiler is updated
89+
// inline def apply[T](inline question: String)(inline op: T)(implicit ctx: Context): T =
6190
inline def apply[T](question: => String)(op: => T)(implicit ctx: Context): T =
6291
apply[T](question, Printers.default, false)(op)
6392

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -818,43 +818,8 @@ trait Checking {
818818
tree.tpe.widenTermRefExpr match {
819819
case tp: ConstantType if exprPurity(tree) >= purityLevel => // ok
820820
case _ =>
821-
tree match {
822-
case Typed(expr, _) =>
823-
checkInlineConformant(expr, isFinal, what)
824-
case Inlined(_, Nil, expr) =>
825-
checkInlineConformant(expr, isFinal, what)
826-
case SeqLiteral(elems, _) =>
827-
elems.foreach(elem => checkInlineConformant(elem, isFinal, what))
828-
case Apply(fn, List(arg)) if defn.WrapArrayMethods().contains(fn.symbol) =>
829-
checkInlineConformant(arg, isFinal, what)
830-
case _ =>
831-
def isCaseClassApply(sym: Symbol): Boolean =
832-
sym.name == nme.apply && sym.is(Synthetic) && sym.owner.is(Module) && sym.owner.companionClass.is(Case)
833-
def isCaseClassNew(sym: Symbol): Boolean =
834-
sym.isPrimaryConstructor && sym.owner.is(Case) && sym.owner.isStatic
835-
def isCaseObject(sym: Symbol): Boolean =
836-
// TODO add alias to Nil in scala package
837-
sym.is(Case) && sym.is(Module)
838-
def isStaticEnumCase(sym: Symbol): Boolean =
839-
sym.is(Enum) && sym.is(JavaStatic) && sym.is(Case)
840-
val allow =
841-
ctx.erasedTypes ||
842-
ctx.inInlineMethod ||
843-
(tree.symbol.isStatic && isCaseObject(tree.symbol) || isCaseClassApply(tree.symbol)) ||
844-
isStaticEnumCase(tree.symbol) ||
845-
isCaseClassNew(tree.symbol)
846-
847-
if (!allow) ctx.error(em"$what must be a known value", tree.sourcePos)
848-
else {
849-
def checkArgs(tree: Tree): Unit = tree match {
850-
case Apply(fn, args) =>
851-
args.foreach(arg => checkInlineConformant(arg, isFinal, what))
852-
checkArgs(fn)
853-
case _ =>
854-
}
855-
checkArgs(tree)
856-
}
857-
}
821+
if (!ctx.erasedTypes && !ctx.inInlineMethod)
822+
ctx.error(em"$what must be a known value", tree.sourcePos)
858823
}
859824
}
860825

compiler/src/dotty/tools/dotc/typer/Inliner.scala

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,8 @@ object Inliner {
208208
}
209209

210210
val Apply(_, codeArg :: Nil) = tree
211-
ConstFold(stripTyped(codeArg.underlyingArgument)).tpe.widenTermRefExpr match {
211+
val underlyingCodeArg = stripTyped(codeArg.underlying)
212+
ConstFold(underlyingCodeArg).tpe.widenTermRefExpr match {
212213
case ConstantType(Constant(code: String)) =>
213214
val source2 = SourceFile.virtual("tasty-reflect", code)
214215
val ctx2 = ctx.fresh.setNewTyperState().setTyper(new Typer).setSource(source2)
@@ -223,7 +224,7 @@ object Inliner {
223224
res ++= typerErrors.map(e => ErrorKind.Typer -> e)
224225
res.toList
225226
case t =>
226-
assert(ctx.reporter.hasErrors) // at least: argument to inline parameter must be a known value
227+
ctx.error("argument to compileError must be a statically known String", underlyingCodeArg.sourcePos)
227228
Nil
228229
}
229230

@@ -333,9 +334,10 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
333334
val argtpe = arg.tpe.dealiasKeepAnnots
334335
val isByName = paramtp.dealias.isInstanceOf[ExprType]
335336
var inlineFlags: FlagSet = InlineProxy
336-
if (paramtp.hasAnnotation(defn.InlineParamAnnot)) inlineFlags |= Inline
337+
if (paramtp.widenExpr.hasAnnotation(defn.InlineParamAnnot)) inlineFlags |= Inline
338+
if (isByName) inlineFlags |= Method
337339
val (bindingFlags, bindingType) =
338-
if (isByName) (InlineByNameProxy.toTermFlags, ExprType(argtpe.widen))
340+
if (isByName) (inlineFlags, ExprType(argtpe.widen))
339341
else (inlineFlags, argtpe.widen)
340342
val boundSym = newSym(name, bindingFlags, bindingType).asTerm
341343
val binding = {
@@ -765,10 +767,8 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
765767
def search(buf: mutable.ListBuffer[ValOrDefDef]) = buf.find(_.name == tree.name)
766768
if (paramProxies.contains(tree.typeOpt))
767769
search(bindingsBuf) match {
768-
case Some(vdef: ValDef) if vdef.symbol.is(Inline) =>
769-
Some(integrate(vdef.rhs, vdef.symbol))
770-
case Some(ddef: DefDef) =>
771-
Some(integrate(ddef.rhs, ddef.symbol))
770+
case Some(bind: ValOrDefDef) if bind.symbol.is(Inline) =>
771+
Some(integrate(bind.rhs, bind.symbol))
772772
case _ => None
773773
}
774774
else None
@@ -1198,7 +1198,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
11981198
val bindingOfSym = newMutableSymbolMap[MemberDef]
11991199

12001200
def isInlineable(binding: MemberDef) = binding match {
1201-
case DefDef(_, Nil, Nil, _, _) => true
1201+
case ddef @ DefDef(_, Nil, Nil, _, _) => isPureExpr(ddef.rhs)
12021202
case vdef @ ValDef(_, _, _) => isPureExpr(vdef.rhs)
12031203
case _ => false
12041204
}
@@ -1236,7 +1236,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
12361236
case Some(x) => x > 1 || x == 1 && !boundSym.is(Method)
12371237
case none => true
12381238
}
1239-
} && !(boundSym.isAllOf(InlineMethod) && boundSym.isOneOf(GivenOrImplicit))
1239+
} && !boundSym.is(Inline)
12401240

12411241
val inlineBindings = new TreeMap {
12421242
override def transform(t: Tree)(implicit ctx: Context) = t match {

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2910,8 +2910,6 @@ class Typer extends Namer
29102910
tree
29112911
}
29122912
else if (tree.tpe.widenExpr <:< pt) {
2913-
if (pt.hasAnnotation(defn.InlineParamAnnot))
2914-
checkInlineConformant(tree, isFinal = false, "argument to inline parameter")
29152913
if (ctx.typeComparer.GADTused && pt.isValueType)
29162914
// Insert an explicit cast, so that -Ycheck in later phases succeeds.
29172915
// I suspect, but am not 100% sure that this might affect inferred types,

compiler/src/dotty/tools/dotc/util/Stats.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import collection.mutable
1919
override def default(key: String): Int = 0
2020
}
2121

22+
// FIXME Use this signature after reference compiler is updated
23+
// inline def record(inline fn: String, inline n: Int = 1): Unit =
2224
inline def record(fn: => String, n: => Int = 1): Unit =
2325
if (enabled) doRecord(fn, n)
2426

@@ -28,16 +30,17 @@ import collection.mutable
2830
hits(name) += n
2931
}
3032

33+
// FIXME Use this signature after reference compiler is updated
34+
// inline def trackTime[T](fn: String)(inline op: T): T =
3135
inline def trackTime[T](fn: String)(op: => T): T =
3236
if (enabled) doTrackTime(fn)(op) else op
3337

3438
def doTrackTime[T](fn: String)(op: => T): T = {
35-
def op1 = op
3639
if (monitored) {
3740
val start = System.nanoTime
38-
try op1 finally record(fn, ((System.nanoTime - start) / 1000).toInt)
41+
try op finally record(fn, ((System.nanoTime - start) / 1000).toInt)
3942
}
40-
else op1
43+
else op
4144
}
4245

4346
final val GroupChar = '/'

0 commit comments

Comments
 (0)