diff options
author | Martin Odersky <odersky@gmail.com> | 2016-09-12 13:01:28 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2016-10-02 16:12:28 +0200 |
commit | 845b689a4a652fa79a7d0621f5ebe15bbf9225c7 (patch) | |
tree | ce308233797b8b032b25c8ed29b6663da8742340 /src/dotty | |
parent | b559aff35d6d365284fc1e05a3ca49a17551df29 (diff) | |
download | dotty-845b689a4a652fa79a7d0621f5ebe15bbf9225c7.tar.gz dotty-845b689a4a652fa79a7d0621f5ebe15bbf9225c7.tar.bz2 dotty-845b689a4a652fa79a7d0621f5ebe15bbf9225c7.zip |
Add inline for vals
- allow inline as an alternative to final for vals
(final is retained for backwards compatibility for now)
- allow inline for parameters
- check that rhs of inline value has a constant type
- check that arguments to inline value parameters have constant type
- check that inline members are not deferred
- make inline members effectively final
Diffstat (limited to 'src/dotty')
-rw-r--r-- | src/dotty/annotation/internal/InlineParam.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Flags.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 15 | ||||
-rw-r--r-- | src/dotty/tools/dotc/parsing/Parsers.scala | 15 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Checking.scala | 9 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 7 |
8 files changed, 54 insertions, 8 deletions
diff --git a/src/dotty/annotation/internal/InlineParam.scala b/src/dotty/annotation/internal/InlineParam.scala new file mode 100644 index 000000000..a144f9edb --- /dev/null +++ b/src/dotty/annotation/internal/InlineParam.scala @@ -0,0 +1,6 @@ +package dotty.annotation.internal + +import scala.annotation.Annotation + +/** An annotation produced by Namer to indicate an inline parameter */ +final class InlineParam() extends Annotation diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 8bf340337..12677edb6 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -468,6 +468,8 @@ class Definitions { def ImplicitNotFoundAnnot(implicit ctx: Context) = ImplicitNotFoundAnnotType.symbol.asClass lazy val InlineAnnotType = ctx.requiredClassRef("scala.inline") def InlineAnnot(implicit ctx: Context) = InlineAnnotType.symbol.asClass + lazy val InlineParamAnnotType = ctx.requiredClassRef("dotty.annotation.internal.InlineParam") + def InlineParamAnnot(implicit ctx: Context) = InlineParamAnnotType.symbol.asClass lazy val InvariantBetweenAnnotType = ctx.requiredClassRef("dotty.annotation.internal.InvariantBetween") def InvariantBetweenAnnot(implicit ctx: Context) = InvariantBetweenAnnotType.symbol.asClass lazy val MigrationAnnotType = ctx.requiredClassRef("scala.annotation.migration") diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index cf3b23c91..1a1182c7b 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -556,6 +556,12 @@ object Flags { /** A type parameter or type parameter accessor */ final val TypeParamOrAccessor = TypeParam | TypeParamAccessor + /** A deferred member or a parameter accessor (these don't have right hand sides) */ + final val DeferredOrParamAccessor = Deferred | ParamAccessor + + /** value that's final or inline */ + final val FinalOrInline = Final | Inline + /** If symbol of a type alias has these flags, prefer the alias */ final val AliasPreferred = TypeParam | BaseTypeArg | ExpandedName diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 0af673561..0c9a12701 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -2419,7 +2419,12 @@ object Types { apply(nme.syntheticParamNames(paramTypes.length), paramTypes)(resultTypeExp) def apply(paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType = apply(nme.syntheticParamNames(paramTypes.length), paramTypes, resultType) + + /** Produce method type from parameter symbols, with special mappings for repeated + * and inline parameters. + */ def fromSymbols(params: List[Symbol], resultType: Type)(implicit ctx: Context) = { + /** Replace @repeated annotations on Seq or Array types by <repeated> types */ def translateRepeated(tp: Type): Type = tp match { case tp @ ExprType(tp1) => tp.derivedExprType(translateRepeated(tp1)) case AnnotatedType(tp, annot) if annot matches defn.RepeatedAnnot => @@ -2429,7 +2434,15 @@ object Types { case tp => tp } - def paramInfo(param: Symbol): Type = translateRepeated(param.info) + /** Add @inlineParam to inline call-by-value parameters */ + def translateInline(tp: Type): Type = tp match { + case tp @ ExprType(tp1) => tp + case _ => AnnotatedType(tp, Annotation(defn.InlineParamAnnot)) + } + def paramInfo(param: Symbol): Type = { + val paramType = translateRepeated(param.info) + if (param.is(Inline)) translateInline(paramType) else paramType + } def transformResult(mt: MethodType) = resultType.subst(params, (0 until params.length).toList map (MethodParam(mt, _))) apply(params map (_.name.asTermName), params map paramInfo)(transformResult _) diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index 2fd79f999..0a25bf801 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1641,12 +1641,13 @@ object Parsers { /** ClsParamClauses ::= {ClsParamClause} [[nl] `(' `implicit' ClsParams `)'] * ClsParamClause ::= [nl] `(' [ClsParams] ')' * ClsParams ::= ClsParam {`' ClsParam} - * ClsParam ::= {Annotation} [{Modifier} (`val' | `var')] id `:' ParamType [`=' Expr] + * ClsParam ::= {Annotation} [{Modifier} (`val' | `var') | `inline'] Param * DefParamClauses ::= {DefParamClause} [[nl] `(' `implicit' DefParams `)'] * DefParamClause ::= [nl] `(' [DefParams] ')' * DefParams ::= DefParam {`,' DefParam} - * DefParam ::= {Annotation} id `:' ParamType [`=' Expr] - */ + * DefParam ::= {Annotation} [`inline'] Param + * Param ::= id `:' ParamType [`=' Expr] + */ def paramClauses(owner: Name, ofCaseClass: Boolean = false): List[List[ValDef]] = { var implicitFlag = EmptyFlags var firstClauseOfCaseClass = ofCaseClass @@ -1665,12 +1666,16 @@ object Parsers { in.nextToken() addFlag(mods, Mutable) } else { - if (!(mods.flags &~ ParamAccessor).isEmpty) syntaxError("`val' or `var' expected") + if (!(mods.flags &~ (ParamAccessor | Inline)).isEmpty) + syntaxError("`val' or `var' expected") if (firstClauseOfCaseClass) mods else mods | PrivateLocal } } } - else mods = atPos(start) { mods | Param } + else { + if (in.token == INLINE) mods = addModifier(mods) + mods = atPos(start) { mods | Param } + } atPos(start, nameStart) { val name = ident() val tpt = diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala index 415cd5d6a..42eede5e9 100644 --- a/src/dotty/tools/dotc/typer/Checking.scala +++ b/src/dotty/tools/dotc/typer/Checking.scala @@ -344,6 +344,7 @@ object Checking { fail(i"only classes can have declared but undefined members$varNote") checkWithDeferred(Private) checkWithDeferred(Final) + checkWithDeferred(Inline) } if (sym.isValueClass && sym.is(Trait) && !sym.isRefinementClass) fail(i"$sym cannot extend AnyVal") @@ -479,6 +480,13 @@ trait Checking { tp } + /** Check that `tree` is a pure expression of constant type */ + def checkInlineConformant(tree: Tree, what: => String)(implicit ctx: Context): Unit = + tree.tpe.widenTermRefExpr match { + case tp: ConstantType if isPureExpr(tree) => // ok + case _ => ctx.error(em"$what must be a constant expression", tree.pos) + } + /** Check that class does not define same symbol twice */ def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = { val seen = new mutable.HashMap[Name, List[Symbol]] { @@ -543,6 +551,7 @@ trait NoChecking extends Checking { override def checkClassType(tp: Type, pos: Position, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type = tp override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = () override def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp + override def checkInlineConformant(tree: Tree, what: => String)(implicit ctx: Context) = () override def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = () override def checkParentCall(call: Tree, caller: ClassSymbol)(implicit ctx: Context) = () override def checkSimpleKinded(tpt: Tree)(implicit ctx: Context): Tree = tpt diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index a33061453..2e714ab6d 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -891,7 +891,7 @@ class Namer { typer: Typer => // println(s"final inherited for $sym: ${inherited.toString}") !!! // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}") - def isInline = sym.is(Final, butNot = Method | Mutable) + def isInline = sym.is(FinalOrInline, butNot = Method | Mutable) // Widen rhs type and approximate `|' but keep ConstantTypes if // definition is inline (i.e. final in Scala2). diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index d99d85fba..58fb47f2c 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1140,6 +1140,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case rhs => typedExpr(rhs, tpt1.tpe) } val vdef1 = assignType(cpy.ValDef(vdef)(name, tpt1, rhs1), sym) + if (sym.is(Inline, butNot = DeferredOrParamAccessor)) + checkInlineConformant(rhs1, "right-hand side of inline value") patchIfLazy(vdef1) vdef1 } @@ -1808,7 +1810,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } tree } - else if (tree.tpe <:< pt) + else if (tree.tpe <:< pt) { + if (pt.hasAnnotation(defn.InlineParamAnnot)) + checkInlineConformant(tree, "argument to inline parameter") if (Inliner.hasBodyToInline(tree.symbol) && !ctx.owner.ownersIterator.exists(_.isInlineMethod) && !ctx.settings.YnoInline.value && @@ -1822,6 +1826,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit tree.asInstance(pt) else tree + } else if (wtp.isInstanceOf[MethodType]) missingArgs else { typr.println(i"adapt to subtype ${tree.tpe} !<:< $pt") |