Skip to content

Commit 6c47bd3

Browse files
TATSUNO Yasuhirosjrd
TATSUNO Yasuhiro
authored andcommitted
Add support for the intersection type A & B (#46)
1 parent ce1982d commit 6c47bd3

File tree

7 files changed

+98
-2
lines changed

7 files changed

+98
-2
lines changed

samples/intersectiontype.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
declare namespace intersectiontype {
2+
3+
type ArchiverOptions = CoreOptions & ExtraOptions & MoreExtraOptions;
4+
type UnionOfIntersection = CoreOptions | CoreOptions & ExtraOptions | CoreOptions & MoreExtraOptions;
5+
type Duplicates = CoreOptions & CoreOptions & ExtraOptions & MoreExtraOptions;
6+
7+
interface CoreOptions {
8+
statConcurrency: number;
9+
}
10+
11+
interface ExtraOptions {
12+
allowHalfOpen: boolean;
13+
}
14+
15+
interface MoreExtraOptions {
16+
store: boolean;
17+
}
18+
19+
export function test(v : CoreOptions & ExtraOptions): CoreOptions & MoreExtraOptions;
20+
21+
}

samples/intersectiontype.ts.scala

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
import scala.scalajs.js
3+
import js.annotation._
4+
import js.|
5+
6+
package intersectiontype {
7+
8+
package intersectiontype {
9+
10+
@js.native
11+
trait CoreOptions extends js.Object {
12+
var statConcurrency: Double = js.native
13+
}
14+
15+
@js.native
16+
trait ExtraOptions extends js.Object {
17+
var allowHalfOpen: Boolean = js.native
18+
}
19+
20+
@js.native
21+
trait MoreExtraOptions extends js.Object {
22+
var store: Boolean = js.native
23+
}
24+
25+
@js.native
26+
@JSGlobal("intersectiontype")
27+
object Intersectiontype extends js.Object {
28+
type ArchiverOptions = CoreOptions with ExtraOptions with MoreExtraOptions
29+
type UnionOfIntersection = CoreOptions | CoreOptions with ExtraOptions | CoreOptions with MoreExtraOptions
30+
type Duplicates = CoreOptions with ExtraOptions with MoreExtraOptions
31+
def test(v: CoreOptions with ExtraOptions): CoreOptions with MoreExtraOptions = js.native
32+
}
33+
34+
}
35+
36+
}

src/main/scala/org/scalajs/tools/tsimporter/Importer.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,17 @@ class Importer(val output: java.io.PrintWriter) {
295295
TypeRef(QualifiedName.Function(params.size), targs)
296296
}
297297

298+
case IntersectionType(left, right) =>
299+
def visit(tpe: TypeTree, visited: List[TypeRef]): List[TypeRef] = {
300+
tpe match {
301+
case IntersectionType(left, right) =>
302+
visit(left, visit(right, visited))
303+
case _ =>
304+
typeToScala(tpe) :: visited
305+
}
306+
}
307+
TypeRef.Intersection(visit(tpe, Nil).distinct)
308+
298309
case UnionType(left, right) =>
299310
def visit(tpe: TypeTree, visited: List[TypeRef]): List[TypeRef] = {
300311
tpe match {

src/main/scala/org/scalajs/tools/tsimporter/Trees.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ object Trees {
151151

152152
case class UnionType(left: TypeTree, right: TypeTree) extends TypeTree
153153

154+
case class IntersectionType(left: TypeTree, right: TypeTree) extends TypeTree
155+
154156
case class TupleType(tparams: List[TypeTree]) extends TypeTree
155157

156158
case class TypeQuery(expr: QualifiedIdent) extends TypeTree

src/main/scala/org/scalajs/tools/tsimporter/parser/TSDefParser.scala

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class TSDefParser extends StdTokenParsers with ImplicitConversions {
4545

4646
lexical.delimiters ++= List(
4747
"{", "}", "(", ")", "[", "]", "<", ">",
48-
".", ";", ",", "?", ":", "=", "|", "*",
48+
".", ";", ",", "?", ":", "=", "|", "&", "*",
4949
// TypeScript-specific
5050
"...", "=>"
5151
)
@@ -190,10 +190,18 @@ class TSDefParser extends StdTokenParsers with ImplicitConversions {
190190
":" ~> typeDesc
191191

192192
lazy val typeDesc: Parser[TypeTree] =
193-
rep1sep(singleTypeDesc, "|") ^^ {
193+
unionTypeDesc
194+
195+
lazy val unionTypeDesc: Parser[TypeTree] =
196+
rep1sep(intersectionTypeDesc, "|") ^^ {
194197
_.reduceLeft(UnionType)
195198
}
196199

200+
lazy val intersectionTypeDesc: Parser[TypeTree] =
201+
rep1sep(singleTypeDesc, "&") ^^ {
202+
_.reduceLeft(IntersectionType)
203+
}
204+
197205
lazy val singleTypeDesc: Parser[TypeTree] =
198206
baseTypeDesc ~ rep("[" ~ "]") ^^ {
199207
case base ~ arrayDims =>

src/main/scala/org/scalajs/tools/tsimporter/sc/Definitions.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ object Name {
2828
val REPEATED = Name("*")
2929
val SINGLETON = Name("<typeof>")
3030
val THIS = Name("<this>")
31+
val INTERSECTION = Name("<with>")
3132
}
3233

3334
case class QualifiedName(parts: Name*) {
@@ -56,6 +57,7 @@ object QualifiedName {
5657
def Function(arity: Int) = scala_js dot Name("Function"+arity)
5758
def Tuple(arity: Int) = scala_js dot Name("Tuple"+arity)
5859
val Union = scala_js dot Name("|")
60+
val Intersection = QualifiedName(Name.INTERSECTION)
5961
}
6062

6163
class Symbol(val name: Name) {
@@ -314,6 +316,18 @@ object TypeRef {
314316
}
315317
}
316318

319+
object Intersection {
320+
def apply(types: List[TypeRef]): TypeRef =
321+
TypeRef(QualifiedName.Intersection, types)
322+
323+
def unapply(typeRef: TypeRef): Option[List[TypeRef]] = typeRef match {
324+
case TypeRef(QualifiedName.Intersection, types) =>
325+
Some(types)
326+
327+
case _ => None
328+
}
329+
}
330+
317331
object Singleton {
318332
def apply(underlying: QualifiedName): TypeRef =
319333
TypeRef(QualifiedName(Name.SINGLETON), List(TypeRef(underlying)))

src/main/scala/org/scalajs/tools/tsimporter/sc/Printer.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ class Printer(private val output: PrintWriter, outputPackage: String) {
197197
implicit val withPipe = ListElemSeparator.Pipe
198198
p"$types"
199199

200+
case TypeRef.Intersection(types) =>
201+
implicit val withWith = ListElemSeparator.WithKeyword
202+
p"$types"
203+
200204
case TypeRef.This =>
201205
p"this.type"
202206

0 commit comments

Comments
 (0)