Skip to content

Commit 70a5209

Browse files
committed
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.
1 parent b2633f9 commit 70a5209

File tree

5 files changed

+48
-6
lines changed

5 files changed

+48
-6
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,19 +157,31 @@ object desugar {
157157
ValDef(epname, tpt, EmptyTree).withFlags(paramFlags | Implicit)
158158
}
159159

160-
/** Expand context bounds to evidence params. E.g.,
160+
/** 1. Expand context bounds to evidence params. E.g.,
161161
*
162162
* def f[T >: L <: H : B](params)
163163
* ==>
164164
* def f[T >: L <: H](params)(implicit evidence$0: B[T])
165165
*
166-
* Expand default arguments to default getters. E.g,
166+
* 2. Expand default arguments to default getters. E.g,
167167
*
168168
* def f[T: B](x: Int = 1)(y: String = x + "m") = ...
169169
* ==>
170170
* def f[T](x: Int)(y: String)(implicit evidence$0: B[T]) = ...
171171
* def f$default$1[T] = 1
172172
* def f$default$2[T](x: Int) = x + "m"
173+
*
174+
* 3. Convert <: T to : T in specializing inline methods. E.g.
175+
*
176+
* inline def f(x: Boolean) <: Any = if (x) 1 else ""
177+
* ==>
178+
* inline def f(x: Boolean): Any = if (x) 1 else ""
179+
*
180+
* 4. Upcast non-specializing inline methods. E.g.
181+
*
182+
* inline def f(x: Boolean): Any = if (x) 1 else ""
183+
* ==>
184+
* inline def f(x: Boolean): Any = (if (x) 1 else ""): Any
173185
*/
174186
private def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false)(implicit ctx: Context): Tree = {
175187
val DefDef(name, tparams, vparamss, tpt, rhs) = meth
@@ -188,7 +200,16 @@ object desugar {
188200
cpy.TypeDef(tparam)(rhs = desugarContextBounds(tparam.rhs))
189201
}
190202

191-
val meth1 = addEvidenceParams(cpy.DefDef(meth)(tparams = tparams1), epbuf.toList)
203+
var meth1 = addEvidenceParams(cpy.DefDef(meth)(tparams = tparams1), epbuf.toList)
204+
205+
if (meth1.mods.is(Inline))
206+
meth1.tpt match {
207+
case TypeBoundsTree(_, tpt1) =>
208+
meth1 = cpy.DefDef(meth1)(tpt = tpt1)
209+
case tpt if !tpt.isEmpty && !meth1.rhs.isEmpty =>
210+
meth1 = cpy.DefDef(meth1)(rhs = Typed(meth1.rhs, tpt))
211+
case _ =>
212+
}
192213

193214
/** The longest prefix of parameter lists in vparamss whose total length does not exceed `n` */
194215
def takeUpTo(vparamss: List[List[ValDef]], n: Int): List[List[ValDef]] = vparamss match {

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2166,7 +2166,7 @@ object Parsers {
21662166
}
21672167
}
21682168

2169-
/** DefDef ::= DefSig (`:' Type [`=' Expr] | "=" Expr)
2169+
/** DefDef ::= DefSig [(‘:’ | ‘<:’) Type] ‘=’ Expr
21702170
* | this ParamClause ParamClauses `=' ConstrExpr
21712171
* DefDcl ::= DefSig `:' Type
21722172
* DefSig ::= id [DefTypeParamClause] ParamClauses
@@ -2195,7 +2195,13 @@ object Parsers {
21952195
val name = ident()
21962196
val tparams = typeParamClauseOpt(ParamOwner.Def)
21972197
val vparamss = paramClauses(name)
2198-
var tpt = fromWithinReturnType(typedOpt())
2198+
var tpt = fromWithinReturnType {
2199+
if (in.token == SUBTYPE && mods.is(Inline)) {
2200+
in.nextToken()
2201+
TypeBoundsTree(EmptyTree, toplevelTyp())
2202+
}
2203+
else typedOpt()
2204+
}
21992205
if (in.isScala2Mode) newLineOptWhenFollowedBy(LBRACE)
22002206
val rhs =
22012207
if (in.token == EQUALS) {

compiler/src/dotty/tools/dotc/transform/Staging.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,7 @@ class Staging extends MacroTransformWithImplicits {
628628
case Select(qual, _) if tree.symbol.isSplice && Splicer.canBeSpliced(qual) => Some(qual)
629629
case Block(List(stat), Literal(Constant(()))) => unapply(stat)
630630
case Block(Nil, expr) => unapply(expr)
631+
case Typed(expr, _) => unapply(expr)
631632
case _ => None
632633
}
633634
}

docs/docs/internals/syntax.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ Def ::= ‘val’ PatDef
329329
PatDef ::= Pattern2 {‘,’ Pattern2} [‘:’ Type] ‘=’ Expr PatDef(_, pats, tpe?, expr)
330330
VarDef ::= PatDef
331331
| ids ‘:’ Type ‘=’ ‘_’
332-
DefDef ::= DefSig [‘:’ Type] ‘=’ Expr DefDef(_, name, tparams, vparamss, tpe, expr)
332+
DefDef ::= DefSig [(‘:’ | ‘<:’) Type] ‘=’ Expr DefDef(_, name, tparams, vparamss, tpe, expr)
333333
| DefSig [nl] ‘{’ Block ‘}’ DefDef(_, name, tparams, vparamss, tpe, Block)
334334
| ‘this’ DefParamClause DefParamClauses DefDef(_, <init>, Nil, vparamss, EmptyTree, expr | Block)
335335
(‘=’ ConstrExpr | [nl] ConstrBlock)

tests/neg/specializing-inline.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
object Test {
2+
3+
inline def h(x: Boolean) = if (x) 1 else ""
4+
val z = h(true)
5+
val zc: Int = z
6+
7+
inline def g <: Any = 1
8+
val y = g
9+
val yc: Int = y // OK
10+
11+
inline def f: Any = 1
12+
val x = f
13+
val xc: Int = x // error
14+
}

0 commit comments

Comments
 (0)