Skip to content

Add match types mixed with staged macro #5065

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
486074a
Add Tuple and *: types
odersky Aug 13, 2018
386b5e1
Add version-specific source directories in the library
smarter Aug 14, 2018
9bd796a
Fix Inlined abbreviation in erased code
odersky Aug 14, 2018
b0f7680
Remove rewrite annotation again
odersky Aug 14, 2018
c455db1
Add generative operations to tuples
odersky Aug 14, 2018
7d474da
Fix TupleXXL equals
odersky Aug 14, 2018
492f80e
More generative operations on Tuples: tail, apply, ++
odersky Aug 14, 2018
eac7792
Erase *: to tuple classes
odersky Aug 14, 2018
e353af9
Allow tuple literals to extend beyond 22
odersky Aug 15, 2018
4ad41d4
Don't generate *: in generic Java signatures
odersky Aug 15, 2018
fadd4b7
Test pattern matching of tuples >= 23.
odersky Aug 16, 2018
d786b4c
Whitelist some Scala-2 classes as pure
odersky Aug 17, 2018
f09ba1b
Fix side-effect handling in reduceProjection
odersky Aug 17, 2018
3bfea78
Support a limited form of rewrite unapplys
odersky Aug 17, 2018
98971a6
Enforce implementation restrictions
odersky Aug 17, 2018
93d5eac
Add MatchType as a type form
odersky Aug 20, 2018
e830298
Represent literals used as types with SingletonTypeTrees
odersky Aug 20, 2018
f5d96a5
Syntax, parsing, and type-checking of match types
odersky Aug 20, 2018
0326709
Fix unpickling of match types
odersky Aug 20, 2018
033e701
Blacklist match type fromtasty test
odersky Aug 20, 2018
fdcbc9f
Classify type defs with matches as RHS as abstract
odersky Aug 22, 2018
04124a9
Implement subtyping for match types
odersky Aug 22, 2018
d17c292
Cache match reduce results
odersky Aug 22, 2018
5bdee62
Cache results of attempts to reduce match types
odersky Aug 23, 2018
1fd37a3
Use a special type for match aliases
odersky Aug 24, 2018
e881350
Applications of erased functions are always pure
odersky Aug 24, 2018
2710e2b
Allow user-defined error diagnostics when rewriting
odersky Aug 24, 2018
a1efa25
Fix two issues when comparing match types
odersky Aug 24, 2018
dc7f447
MatchType reorg
odersky Aug 27, 2018
a19e2cc
Typelevel natural numbers
odersky Aug 27, 2018
a345e9e
Reduce matches on creation
odersky Aug 27, 2018
d34e3fa
Handle MatchTypeTrees in ExtractAPI
odersky Aug 29, 2018
825db1b
Refine matchtype reduction caching
odersky Aug 29, 2018
da4b5e8
Coarser variance checking for match types
odersky Aug 29, 2018
fbb173f
Add constValue function
odersky Aug 29, 2018
e1a2e61
Add NonEmptyTuple abstract class
odersky Aug 29, 2018
1a31183
More precise derivesFrom for MatchTypes
odersky Aug 29, 2018
0f5e82b
Base Tuple computations on types
odersky Aug 29, 2018
8daf613
Make MatchTypes value types
odersky Aug 29, 2018
97e0f3b
Fix inlining of parameters of singleton type
odersky Aug 29, 2018
5284fe8
Test tuples2 needs to run with -Yno-deep-subtypes
odersky Aug 29, 2018
86e17fb
Add constValueOpt method
odersky Aug 29, 2018
5c2a105
Fix unpickling of match type aliases
odersky Aug 29, 2018
2e9cd7d
Survive bottom values in pattern matches
odersky Aug 29, 2018
d34c45e
Report rewrite errors at outermost rewrite call
odersky Aug 29, 2018
39b86e3
Harden Tuple operations against wrong inputs
odersky Aug 29, 2018
dd0d0eb
Reduce sizes of tuples of tuples2.scala
odersky Aug 29, 2018
e583c9c
Experiment with type matches and staged macros
nicolasstucki Aug 30, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bench/src/main/scala/Benchmarks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ object Bench {

val opts = new OptionsBuilder()
.shouldFailOnError(true)
.jvmArgs("-Xms2G", "-Xmx2G")
.jvmArgs("-Xms2G", "-Xmx2G", "-Xss10m")
.mode(Mode.AverageTime)
.timeUnit(TimeUnit.MILLISECONDS)
.warmupIterations(warmup)
Expand Down
27 changes: 17 additions & 10 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,23 @@ object desugar {
makeOp(right, left, Position(op.pos.start, right.pos.end))
}

/** Translate tuple expressions of arity <= 22
*
* () ==> ()
* (t) ==> t
* (t1, ..., tN) ==> TupleN(t1, ..., tN)
*/
def smallTuple(tree: Tuple)(implicit ctx: Context): Tree = {
val ts = tree.trees
val arity = ts.length
assert(arity <= Definitions.MaxTupleArity)
def tupleTypeRef = defn.TupleType(arity)
if (arity == 1) ts.head
else if (ctx.mode is Mode.Type) AppliedTypeTree(ref(tupleTypeRef), ts)
else if (arity == 0) unitLiteral
else Apply(ref(tupleTypeRef.classSymbol.companionModule.termRef), ts)
}

/** Make closure corresponding to function.
* params => body
* ==>
Expand Down Expand Up @@ -1141,16 +1158,6 @@ object desugar {
case PrefixOp(op, t) =>
val nspace = if (ctx.mode.is(Mode.Type)) tpnme else nme
Select(t, nspace.UNARY_PREFIX ++ op.name)
case Tuple(ts) =>
val arity = ts.length
def tupleTypeRef = defn.TupleType(arity)
if (arity > Definitions.MaxTupleArity) {
ctx.error(TupleTooLong(ts), tree.pos)
unitLiteral
} else if (arity == 1) ts.head
else if (ctx.mode is Mode.Type) AppliedTypeTree(ref(tupleTypeRef), ts)
else if (arity == 0) unitLiteral
else Apply(ref(tupleTypeRef.classSymbol.companionModule.termRef), ts)
case WhileDo(cond, body) =>
// { <label> def while$(): Unit = if (cond) { body; while$() } ; while$() }
val call = Apply(Ident(nme.WHILE_PREFIX), Nil).withPos(tree.pos)
Expand Down
23 changes: 19 additions & 4 deletions compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped]
case mdef: TypeDef =>
def isBounds(rhs: Tree): Boolean = rhs match {
case _: TypeBoundsTree => true
case _: MatchTypeTree => true // Typedefs with Match rhs classify as abstract
case LambdaTypeTree(_, body) => isBounds(body)
case _ => false
}
Expand Down Expand Up @@ -392,20 +393,21 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
case Ident(_) =>
refPurity(tree)
case Select(qual, _) =>
refPurity(tree).min(exprPurity(qual))
if (tree.symbol.is(Erased)) Pure
else refPurity(tree).min(exprPurity(qual))
case New(_) =>
SimplyPure
case TypeApply(fn, _) =>
exprPurity(fn)
if (fn.symbol.is(Erased)) Pure else exprPurity(fn)
case Apply(fn, args) =>
def isKnownPureOp(sym: Symbol) =
sym.owner.isPrimitiveValueClass || sym.owner == defn.StringClass
if (tree.tpe.isInstanceOf[ConstantType] && isKnownPureOp(tree.symbol)
// A constant expression with pure arguments is pure.
|| fn.symbol.isStable)
minOf(exprPurity(fn), args.map(exprPurity)) `min` Pure
else
Impure
else if (fn.symbol.is(Erased)) Pure
else Impure
case Typed(expr, _) =>
exprPurity(expr)
case Block(stats, expr) =>
Expand Down Expand Up @@ -716,6 +718,19 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
Nil
}

/** If `tree` is an instance of `TupleN[...](e1, ..., eN)`, the arguments `e1, ..., eN`
* otherwise the empty list.
*/
def tupleArgs(tree: Tree)(implicit ctx: Context): List[Tree] = tree match {
case Block(Nil, expr) => tupleArgs(expr)
case Inlined(_, Nil, expr) => tupleArgs(expr)
case Apply(fn, args)
if fn.symbol.name == nme.apply &&
fn.symbol.owner.is(Module) &&
defn.isTupleClass(fn.symbol.owner.companionClass) => args
case _ => Nil
}

/** The qualifier part of a Select or Ident.
* For an Ident, this is the `This` of the current class.
*/
Expand Down
15 changes: 15 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,12 @@ object Trees {
type ThisTree[-T >: Untyped] = LambdaTypeTree[T]
}

/** [bound] selector match { cases } */
case class MatchTypeTree[-T >: Untyped] private[ast] (bound: Tree[T], selector: Tree[T], cases: List[CaseDef[T]])
extends TypTree[T] {
type ThisTree[-T >: Untyped] = MatchTypeTree[T]
}

/** => T */
case class ByNameTypeTree[-T >: Untyped] private[ast] (result: Tree[T])
extends TypTree[T] {
Expand Down Expand Up @@ -916,6 +922,7 @@ object Trees {
type RefinedTypeTree = Trees.RefinedTypeTree[T]
type AppliedTypeTree = Trees.AppliedTypeTree[T]
type LambdaTypeTree = Trees.LambdaTypeTree[T]
type MatchTypeTree = Trees.MatchTypeTree[T]
type ByNameTypeTree = Trees.ByNameTypeTree[T]
type TypeBoundsTree = Trees.TypeBoundsTree[T]
type Bind = Trees.Bind[T]
Expand Down Expand Up @@ -1099,6 +1106,10 @@ object Trees {
case tree: LambdaTypeTree if (tparams eq tree.tparams) && (body eq tree.body) => tree
case _ => finalize(tree, untpd.LambdaTypeTree(tparams, body))
}
def MatchTypeTree(tree: Tree)(bound: Tree, selector: Tree, cases: List[CaseDef]): MatchTypeTree = tree match {
case tree: MatchTypeTree if (bound eq tree.bound) && (selector eq tree.selector) && (cases eq tree.cases) => tree
case _ => finalize(tree, untpd.MatchTypeTree(bound, selector, cases))
}
def ByNameTypeTree(tree: Tree)(result: Tree): ByNameTypeTree = tree match {
case tree: ByNameTypeTree if result eq tree.result => tree
case _ => finalize(tree, untpd.ByNameTypeTree(result))
Expand Down Expand Up @@ -1255,6 +1266,8 @@ object Trees {
case LambdaTypeTree(tparams, body) =>
implicit val ctx = localCtx
cpy.LambdaTypeTree(tree)(transformSub(tparams), transform(body))
case MatchTypeTree(bound, selector, cases) =>
cpy.MatchTypeTree(tree)(transform(bound), transform(selector), transformSub(cases))
case ByNameTypeTree(result) =>
cpy.ByNameTypeTree(tree)(transform(result))
case TypeBoundsTree(lo, hi) =>
Expand Down Expand Up @@ -1389,6 +1402,8 @@ object Trees {
case LambdaTypeTree(tparams, body) =>
implicit val ctx = localCtx
this(this(x, tparams), body)
case MatchTypeTree(bound, selector, cases) =>
this(this(this(x, bound), selector), cases)
case ByNameTypeTree(result) =>
this(x, result)
case TypeBoundsTree(lo, hi) =>
Expand Down
18 changes: 12 additions & 6 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}

def CaseDef(pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef =
ta.assignType(untpd.CaseDef(pat, guard, body), body)
ta.assignType(untpd.CaseDef(pat, guard, body), pat, body)

def Match(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match =
ta.assignType(untpd.Match(selector, cases), cases)
ta.assignType(untpd.Match(selector, cases), selector, cases)

def Labeled(bind: Bind, expr: Tree)(implicit ctx: Context): Labeled =
ta.assignType(untpd.Labeled(bind, expr))
Expand Down Expand Up @@ -165,6 +165,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def LambdaTypeTree(tparams: List[TypeDef], body: Tree)(implicit ctx: Context): LambdaTypeTree =
ta.assignType(untpd.LambdaTypeTree(tparams, body), tparams, body)

def MatchTypeTree(bound: Tree, selector: Tree, cases: List[CaseDef])(implicit ctx: Context): MatchTypeTree =
ta.assignType(untpd.MatchTypeTree(bound, selector, cases), bound, selector, cases)

def TypeBoundsTree(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree =
ta.assignType(untpd.TypeBoundsTree(lo, hi), lo, hi)

Expand Down Expand Up @@ -575,7 +578,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}
}


override def Closure(tree: Tree)(env: List[Tree], meth: Tree, tpt: Tree)(implicit ctx: Context): Closure = {
val tree1 = untpd.cpy.Closure(tree)(env, meth, tpt)
tree match {
Expand All @@ -584,19 +586,20 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
case _ => ta.assignType(tree1, meth, tpt)
}
}

override def Match(tree: Tree)(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match = {
val tree1 = untpd.cpy.Match(tree)(selector, cases)
tree match {
case tree: Match if sameTypes(cases, tree.cases) => tree1.withTypeUnchecked(tree.tpe)
case _ => ta.assignType(tree1, cases)
case _ => ta.assignType(tree1, selector, cases)
}
}

override def CaseDef(tree: Tree)(pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef = {
val tree1 = untpd.cpy.CaseDef(tree)(pat, guard, body)
tree match {
case tree: CaseDef if body.tpe eq tree.body.tpe => tree1.withTypeUnchecked(tree.tpe)
case _ => ta.assignType(tree1, body)
case _ => ta.assignType(tree1, pat, body)
}
}

Expand Down Expand Up @@ -821,7 +824,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {

/** `tree == that` */
def equal(that: Tree)(implicit ctx: Context) =
applyOverloaded(tree, nme.EQ, that :: Nil, Nil, defn.BooleanType)
if (that.tpe.widen.isRef(defn.NothingClass))
Literal(Constant(false))
else
applyOverloaded(tree, nme.EQ, that :: Nil, Nil, defn.BooleanType)

/** `tree.isInstanceOf[tp]`, with special treatment of singleton types */
def isInstance(tp: Type)(implicit ctx: Context): Tree = tp.dealias match {
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def RefinedTypeTree(tpt: Tree, refinements: List[Tree]): RefinedTypeTree = new RefinedTypeTree(tpt, refinements)
def AppliedTypeTree(tpt: Tree, args: List[Tree]): AppliedTypeTree = new AppliedTypeTree(tpt, args)
def LambdaTypeTree(tparams: List[TypeDef], body: Tree): LambdaTypeTree = new LambdaTypeTree(tparams, body)
def MatchTypeTree(bound: Tree, selector: Tree, cases: List[CaseDef]): MatchTypeTree = new MatchTypeTree(bound, selector, cases)
def ByNameTypeTree(result: Tree): ByNameTypeTree = new ByNameTypeTree(result)
def TypeBoundsTree(lo: Tree, hi: Tree): TypeBoundsTree = new TypeBoundsTree(lo, hi)
def Bind(name: Name, body: Tree): Bind = new Bind(name, body)
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/config/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ object Config {
final val cacheAsSeenFrom = true
final val cacheMemberNames = true
final val cacheImplicitScopes = true
final val cacheMatchReduced = true

final val checkCacheMembersNamed = false

Expand Down
Loading