From a4b17095cd04e92a87ef78646aace8742be2d94e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 16 Feb 2019 22:06:19 +0100 Subject: [PATCH 01/14] Check for illegal wildcards in TypeAssigner Drop previous checking in Parser. The idea is that the parser should follow the syntax. Checking conditions that are not reflected in the syntax should come later. --- .../dotty/tools/dotc/core/Definitions.scala | 10 +++++++++ .../dotty/tools/dotc/parsing/Parsers.scala | 21 ++++--------------- .../src/dotty/tools/dotc/typer/Checking.scala | 5 +++++ .../dotty/tools/dotc/typer/TypeAssigner.scala | 6 +++--- tests/neg/i4373.scala | 4 ++-- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index ff380a4b534d..3e2d20a111c2 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -153,6 +153,11 @@ class Definitions { sym } + private def enterBinaryAlias(name: TypeName, op: (Type, Type) => Type): TypeSymbol = + enterAliasType(name, + HKTypeLambda(TypeBounds.empty :: TypeBounds.empty :: Nil)( + tl => op(tl.paramRefs(0), tl.paramRefs(1)))) + private def enterPolyMethod(cls: ClassSymbol, name: TermName, typeParamCount: Int, resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags, useCompleter: Boolean = false) = { @@ -322,6 +327,9 @@ class Definitions { } def AnyKindType: TypeRef = AnyKindClass.typeRef + lazy val andType: TypeSymbol = enterBinaryAlias(tpnme.AND, AndType(_, _)) + lazy val orType: TypeSymbol = enterBinaryAlias(tpnme.OR, OrType(_, _)) + /** Marker method to indicate an argument to a call-by-name parameter. * Created by byNameClosures and elimByName, eliminated by Erasure, */ @@ -1326,6 +1334,8 @@ class Definitions { AnyClass, AnyRefAlias, AnyKindClass, + andType, + orType, RepeatedParamClass, ByNameParamClass2x, AnyValClass, diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 76c727a00a7e..262e0bcd47bf 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -492,9 +492,9 @@ object Parsers { val l = opInfo.operand val r = top if (isType && !op.isBackquoted && op.name == tpnme.raw.BAR) { - OrTypeTree(checkAndOrArgument(l), checkAndOrArgument(r)) + OrTypeTree(l, r) } else if (isType && !op.isBackquoted && op.name == tpnme.raw.AMP) { - AndTypeTree(checkAndOrArgument(l), checkAndOrArgument(r)) + AndTypeTree(l, r) } else InfixOp(l, op, r) } @@ -830,7 +830,7 @@ object Parsers { t } } - val tuple = atSpan(start) { makeTupleOrParens(ts) } + val tuple = atSpan(start) { makeTupleOrParens(ts1) } infixTypeRest( refinedTypeRest( withTypeRest( @@ -898,7 +898,7 @@ object Parsers { if (ctx.settings.strict.value) deprecationWarning(DeprecatedWithOperator()) in.nextToken() - AndTypeTree(checkAndOrArgument(t), checkAndOrArgument(withType())) + AndTypeTree(t, withType()) } else t @@ -1091,19 +1091,6 @@ object Parsers { else rejectWildcard(t, fallbackTree) - def checkAndOrArgument(t: Tree): Tree = - findNonValueTypeTree(t, true) match { - case Some(typTree) => - typTree match { - case typTree: TypeBoundsTree => - syntaxError(UnboundWildcardType(), typTree.span) - case typTree: ByNameTypeTree => - syntaxError(ByNameParameterNotSupported(typTree), typTree.span) - } - scalaAny - case None => t - } - /* ----------- EXPRESSIONS ------------------------------------------------ */ /** EqualsExpr ::= `=' Expr diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 226d40b6f875..904c2fe4190f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -92,6 +92,11 @@ object Checking { checkValidIfApply(ctx.addMode(Mode.AllowLambdaWildcardApply)) } + def checkNoWildcard(tree: Tree)(implicit ctx: Context): Tree = tree.tpe match { + case tpe: TypeBounds => errorTree(tree, "no wildcard type allowed here") + case _ => tree + } + /** Check that kind of `arg` has the same outline as the kind of paramBounds. * E.g. if `paramBounds` has kind * -> *, `arg` must have that kind as well, * and analogously for all other kinds. This kind checking does not take into account diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index c04ac8e97af7..3ce98ff1cca3 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -13,7 +13,7 @@ import ast.Trees._ import NameOps._ import collection.mutable import reporting.diagnostic.messages._ -import Checking.checkNoPrivateLeaks +import Checking.{checkNoPrivateLeaks, checkNoWildcard} trait TypeAssigner { import tpd._ @@ -519,10 +519,10 @@ trait TypeAssigner { tree.withType(ref.tpe) def assignType(tree: untpd.AndTypeTree, left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree = - tree.withType(AndType(left.tpe, right.tpe)) + tree.withType(AndType(checkNoWildcard(left).tpe, checkNoWildcard(right).tpe)) def assignType(tree: untpd.OrTypeTree, left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree = - tree.withType(OrType(left.tpe, right.tpe)) + tree.withType(OrType(checkNoWildcard(left).tpe, checkNoWildcard(right).tpe)) /** Assign type of RefinedType. * Refinements are typed as if they were members of refinement class `refineCls`. diff --git a/tests/neg/i4373.scala b/tests/neg/i4373.scala index 6ba7c81a617a..84b6a71666b2 100644 --- a/tests/neg/i4373.scala +++ b/tests/neg/i4373.scala @@ -41,8 +41,8 @@ object Test { type T19 = (_ with Int) @ annotation.tailrec // error type T20 = (Int with _) @ annotation.tailrec // error - type T21 = Int @ (_ with annotation.tailrec) // error // error - type T22 = Int @ (annotation.tailrec with _) // error // error + type T21 = Int @ (_ with annotation.tailrec) // error + type T22 = Int @ (annotation.tailrec with _) // error type T23 = (_ & Int) @ annotation.tailrec // error type T24 = (Int & _) @ annotation.tailrec // error From a8afd92722ff2e012b6ea4b7fc5cb1767bcc81e9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 17 Feb 2019 10:12:39 +0100 Subject: [PATCH 02/14] Refinements to wildcard checking Simplify and cover cases that were missing (see gadt-GadtStatic.scala). --- .../dotty/tools/dotc/parsing/Parsers.scala | 83 +++++++++---------- tests/pos/gadt-GadtStlc.scala | 2 +- 2 files changed, 39 insertions(+), 46 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 262e0bcd47bf..24e95eddb270 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -423,6 +423,19 @@ object Parsers { case _ => false } + def isWildcardType(t: Tree): Boolean = t match { + case t: TypeBoundsTree => true + case Parens(t1) => isWildcardType(t1) + case _ => false + } + + def rejectWildcardType(t: Tree, fallbackTree: Tree = scalaAny): Tree = + if (isWildcardType(t)) { + syntaxError(UnboundWildcardType(), t.span) + fallbackTree + } + else t + /* -------------- XML ---------------------------------------------------- */ /** the markup parser */ @@ -768,7 +781,7 @@ object Parsers { /** Same as [[typ]], but if this results in a wildcard it emits a syntax error and * returns a tree for type `Any` instead. */ - def toplevelTyp(): Tree = checkWildcard(typ()) + def toplevelTyp(): Tree = rejectWildcardType(typ()) /** Type ::= FunTypeMods FunArgTypes `=>' Type * | HkTypeParamClause `->' Type @@ -885,7 +898,7 @@ object Parsers { def refinedTypeRest(t: Tree): Tree = { newLineOptWhenFollowedBy(LBRACE) - if (in.token == LBRACE) refinedTypeRest(atSpan(startOffset(t)) { RefinedTypeTree(checkWildcard(t), refinement()) }) + if (in.token == LBRACE) refinedTypeRest(atSpan(startOffset(t)) { RefinedTypeTree(rejectWildcardType(t), refinement()) }) else t } @@ -907,7 +920,10 @@ object Parsers { def annotType(): Tree = annotTypeRest(simpleType()) def annotTypeRest(t: Tree): Tree = - if (in.token == AT) annotTypeRest(atSpan(startOffset(t)) { Annotated(t, annot()) }) + if (in.token == AT) + annotTypeRest(atSpan(startOffset(t)) { + Annotated(rejectWildcardType(t), annot()) + }) else t /** SimpleType ::= SimpleType TypeArgs @@ -949,7 +965,7 @@ object Parsers { private def simpleTypeRest(t: Tree): Tree = in.token match { case HASH => simpleTypeRest(typeProjection(t)) case LBRACKET => simpleTypeRest(atSpan(startOffset(t)) { - AppliedTypeTree(checkWildcard(t), typeArgs(namedOK = false, wildOK = true)) }) + AppliedTypeTree(rejectWildcardType(t), typeArgs(namedOK = false, wildOK = true)) }) case _ => t } @@ -959,18 +975,23 @@ object Parsers { atSpan(startOffset(t), startOffset(id)) { Select(t, id.name) } } - /** NamedTypeArg ::= id `=' Type - */ - val namedTypeArg: () => NamedArg = () => { - val name = ident() - accept(EQUALS) - NamedArg(name.toTypeName, typ()) - } - /** ArgTypes ::= Type {`,' Type} * | NamedTypeArg {`,' NamedTypeArg} + * NamedTypeArg ::= id `=' Type */ def argTypes(namedOK: Boolean, wildOK: Boolean): List[Tree] = { + + def argType() = { + val t = typ() + if (wildOK) t else rejectWildcardType(t) + } + + def namedTypeArg() = { + val name = ident() + accept(EQUALS) + NamedArg(name.toTypeName, argType()) + } + def otherArgs(first: Tree, arg: () => Tree): List[Tree] = { val rest = if (in.token == COMMA) { @@ -980,16 +1001,15 @@ object Parsers { else Nil first :: rest } - def typParser() = checkWildcard(typ(), wildOK) if (namedOK && in.token == IDENTIFIER) - typParser() match { + argType() match { case Ident(name) if in.token == EQUALS => in.nextToken() - otherArgs(NamedArg(name, typ()), namedTypeArg) + otherArgs(NamedArg(name, argType()), () => namedTypeArg()) case firstArg => - otherArgs(firstArg, () => typ()) + otherArgs(firstArg, () => argType()) } - else commaSeparated(() => typParser()) + else commaSeparated(() => argType()) } /** FunArgType ::= Type | `=>' Type @@ -1064,33 +1084,6 @@ object Parsers { else if (location == Location.InPattern) refinedType() else infixType() - /** Checks whether `t` represents a non-value type (wildcard types, or ByNameTypeTree). - * If it is, returns the [[Tree]] which immediately represents the non-value type. - */ - @tailrec - private final def findNonValueTypeTree(t: Tree, alsoNonValue: Boolean): Option[Tree] = t match { - case TypeBoundsTree(_, _) => Some(t) - case ByNameTypeTree(_) if alsoNonValue => Some(t) - case Parens(t1) => findNonValueTypeTree(t1, alsoNonValue) - case Annotated(t1, _) => findNonValueTypeTree(t1, alsoNonValue) - case _ => None - } - - def rejectWildcard(t: Tree, fallbackTree: Tree): Tree = - findNonValueTypeTree(t, false) match { - case Some(wildcardTree) => - syntaxError(UnboundWildcardType(), wildcardTree.span) - fallbackTree - case None => t - } - - - def checkWildcard(t: Tree, wildOK: Boolean = false, fallbackTree: Tree = scalaAny): Tree = - if (wildOK) - t - else - rejectWildcard(t, fallbackTree) - /* ----------- EXPRESSIONS ------------------------------------------------ */ /** EqualsExpr ::= `=' Expr @@ -2567,7 +2560,7 @@ object Parsers { */ val constrApp: () => Tree = () => { // Using Ident(nme.ERROR) to avoid causing cascade errors on non-user-written code - val t = checkWildcard(annotType(), fallbackTree = Ident(nme.ERROR)) + val t = rejectWildcardType(annotType(), fallbackTree = Ident(nme.ERROR)) if (in.token == LPAREN) parArgumentExprss(wrapNew(t)) else t } diff --git a/tests/pos/gadt-GadtStlc.scala b/tests/pos/gadt-GadtStlc.scala index 32e6f5630d6b..e51c5f61bf90 100644 --- a/tests/pos/gadt-GadtStlc.scala +++ b/tests/pos/gadt-GadtStlc.scala @@ -119,7 +119,7 @@ object GadtStlc { case Left(isv1) => progress(dapp.d2) match { case Right(r2) => Right(EApp2(isv1, r2)) case Left(isv2) => followsIsLambda(isv1, dapp.d1) match { - case _: ISLAMBDAC[x, e] => Right(EAppAbs[x, e, b, _](isv2)) + case _: ISLAMBDAC[x, e] => Right(EAppAbs[X = x, E = e, V2 = b](isv2)) } } } From a1029216beb8f84ed94fa6c3ea811af3ac508f68 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 17 Feb 2019 12:22:31 +0100 Subject: [PATCH 03/14] Fix test Another test slipped through. It seems using `_` for "inferred argument" is quite popular, even though it's not supported by the language. --- tests/run-with-compiler-custom-args/staged-streams_1.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-with-compiler-custom-args/staged-streams_1.scala b/tests/run-with-compiler-custom-args/staged-streams_1.scala index 101433ddf317..775b2856541d 100644 --- a/tests/run-with-compiler-custom-args/staged-streams_1.scala +++ b/tests/run-with-compiler-custom-args/staged-streams_1.scala @@ -358,10 +358,10 @@ object Test { Linear(zip_producer(producer1, producer2)) case (Linear(producer1), Nested(producer2, nestf2)) => - pushLinear[Expr[A], _, B](producer1, producer2, nestf2) + pushLinear[A = Expr[A], C = B](producer1, producer2, nestf2) case (Nested(producer1, nestf1), Linear(producer2)) => - mapRaw[(B, Expr[A]), (Expr[A], B)]((t => k => '{ ~k((t._2, t._1)) }), pushLinear[B, _, Expr[A]](producer2, producer1, nestf1)) + mapRaw[(B, Expr[A]), (Expr[A], B)]((t => k => '{ ~k((t._2, t._1)) }), pushLinear[A = B, C = Expr[A]](producer2, producer1, nestf1)) case (Nested(producer1, nestf1), Nested(producer2, nestf2)) => zipRaw[A, B](Linear(makeLinear(stream1)), stream2) From e4bd16f46fd8938558fd983d12b906af38f36f68 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 17 Feb 2019 12:12:43 +0100 Subject: [PATCH 04/14] Drop OrTypeTree --- .../src/dotty/tools/dotc/ast/TreeInfo.scala | 1 - compiler/src/dotty/tools/dotc/ast/Trees.scala | 15 ----------- compiler/src/dotty/tools/dotc/ast/tpd.scala | 3 --- compiler/src/dotty/tools/dotc/ast/untpd.scala | 1 - .../tools/dotc/core/tasty/TastyFormat.scala | 4 --- .../tools/dotc/core/tasty/TreePickler.scala | 3 --- .../tools/dotc/core/tasty/TreeUnpickler.scala | 2 -- .../dotty/tools/dotc/parsing/Parsers.scala | 4 +-- .../tools/dotc/printing/RefinedPrinter.scala | 7 ++--- .../tools/dotc/tastyreflect/CoreImpl.scala | 1 - .../TypeOrBoundsTreesOpsImpl.scala | 27 +------------------ .../tools/dotc/transform/TreeChecker.scala | 1 - .../dotty/tools/dotc/typer/TypeAssigner.scala | 6 ++--- .../src/dotty/tools/dotc/typer/Typer.scala | 20 +++++++------- .../src/scala/tasty/reflect/Printers.scala | 6 ++--- .../src/scala/tasty/reflect/TreeUtils.scala | 3 --- .../tasty/reflect/TypeOrBoundsTreeOps.scala | 21 +-------------- tests/neg/and-wildcard.scala | 6 +++++ 18 files changed, 26 insertions(+), 105 deletions(-) create mode 100644 tests/neg/and-wildcard.scala diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index b4637ff1516d..40a04ba5e8e0 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -167,7 +167,6 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => /** can this type be a type pattern? */ def mayBeTypePat(tree: Tree): Boolean = unsplice(tree) match { case AndTypeTree(tpt1, tpt2) => mayBeTypePat(tpt1) || mayBeTypePat(tpt2) - case OrTypeTree(tpt1, tpt2) => mayBeTypePat(tpt1) || mayBeTypePat(tpt2) case RefinedTypeTree(tpt, refinements) => mayBeTypePat(tpt) || refinements.exists(_.isInstanceOf[Bind]) case AppliedTypeTree(tpt, args) => mayBeTypePat(tpt) || args.exists(_.isInstanceOf[Bind]) case Select(tpt, _) => mayBeTypePat(tpt) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 6589104fb158..ade76d9e00cd 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -632,12 +632,6 @@ object Trees { type ThisTree[-T >: Untyped] = AndTypeTree[T] } - /** left | right */ - case class OrTypeTree[-T >: Untyped] private[ast] (left: Tree[T], right: Tree[T])(implicit @constructorOnly src: SourceFile) - extends TypTree[T] { - type ThisTree[-T >: Untyped] = OrTypeTree[T] - } - /** tpt { refinements } */ case class RefinedTypeTree[-T >: Untyped] private[ast] (tpt: Tree[T], refinements: List[Tree[T]])(implicit @constructorOnly src: SourceFile) extends ProxyTree[T] with TypTree[T] { @@ -935,7 +929,6 @@ object Trees { type TypeTree = Trees.TypeTree[T] type SingletonTypeTree = Trees.SingletonTypeTree[T] type AndTypeTree = Trees.AndTypeTree[T] - type OrTypeTree = Trees.OrTypeTree[T] type RefinedTypeTree = Trees.RefinedTypeTree[T] type AppliedTypeTree = Trees.AppliedTypeTree[T] type LambdaTypeTree = Trees.LambdaTypeTree[T] @@ -1106,10 +1099,6 @@ object Trees { case tree: AndTypeTree if (left eq tree.left) && (right eq tree.right) => tree case _ => finalize(tree, untpd.AndTypeTree(left, right)(sourceFile(tree))) } - def OrTypeTree(tree: Tree)(left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree = tree match { - case tree: OrTypeTree if (left eq tree.left) && (right eq tree.right) => tree - case _ => finalize(tree, untpd.OrTypeTree(left, right)(sourceFile(tree))) - } def RefinedTypeTree(tree: Tree)(tpt: Tree, refinements: List[Tree])(implicit ctx: Context): RefinedTypeTree = tree match { case tree: RefinedTypeTree if (tpt eq tree.tpt) && (refinements eq tree.refinements) => tree case _ => finalize(tree, untpd.RefinedTypeTree(tpt, refinements)(sourceFile(tree))) @@ -1273,8 +1262,6 @@ object Trees { cpy.SingletonTypeTree(tree)(transform(ref)) case AndTypeTree(left, right) => cpy.AndTypeTree(tree)(transform(left), transform(right)) - case OrTypeTree(left, right) => - cpy.OrTypeTree(tree)(transform(left), transform(right)) case RefinedTypeTree(tpt, refinements) => cpy.RefinedTypeTree(tree)(transform(tpt), transformSub(refinements)) case AppliedTypeTree(tpt, args) => @@ -1401,8 +1388,6 @@ object Trees { this(x, ref) case AndTypeTree(left, right) => this(this(x, left), right) - case OrTypeTree(left, right) => - this(this(x, left), right) case RefinedTypeTree(tpt, refinements) => this(this(x, tpt), refinements) case AppliedTypeTree(tpt, args) => diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 1c9d0d77ae23..9479590ad01b 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -164,9 +164,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def AndTypeTree(left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree = ta.assignType(untpd.AndTypeTree(left, right), left, right) - def OrTypeTree(left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree = - ta.assignType(untpd.OrTypeTree(left, right), left, right) - def RefinedTypeTree(parent: Tree, refinements: List[Tree], refineCls: ClassSymbol)(implicit ctx: Context): Tree = ta.assignType(untpd.RefinedTypeTree(parent, refinements), parent, refinements, refineCls) diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 8dee85adb6b7..cb444d085019 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -310,7 +310,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def TypeTree()(implicit src: SourceFile): TypeTree = new TypeTree() def SingletonTypeTree(ref: Tree)(implicit src: SourceFile): SingletonTypeTree = new SingletonTypeTree(ref) def AndTypeTree(left: Tree, right: Tree)(implicit src: SourceFile): AndTypeTree = new AndTypeTree(left, right) - def OrTypeTree(left: Tree, right: Tree)(implicit src: SourceFile): OrTypeTree = new OrTypeTree(left, right) def RefinedTypeTree(tpt: Tree, refinements: List[Tree])(implicit src: SourceFile): RefinedTypeTree = new RefinedTypeTree(tpt, refinements) def AppliedTypeTree(tpt: Tree, args: List[Tree])(implicit src: SourceFile): AppliedTypeTree = new AppliedTypeTree(tpt, args) def LambdaTypeTree(tparams: List[TypeDef], body: Tree)(implicit src: SourceFile): LambdaTypeTree = new LambdaTypeTree(tparams, body) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index b8edb41b0c4c..561989682f64 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -107,7 +107,6 @@ Standard-Section: "ASTs" TopLevelStat* TYPEBOUNDStpt Length low_Term high_Term? ANNOTATEDtpt Length underlying_Term fullAnnotation_Term ANDtpt Length left_Term right_Term - ORtpt Length left_Term right_Term MATCHtpt Length bound_Term? sel_Term CaseDef* BYNAMEtpt underlying_Term SHAREDterm term_ASTRef @@ -421,7 +420,6 @@ object TastyFormat { final val ANDtype = 165 final val ANDtpt = 166 final val ORtype = 167 - final val ORtpt = 168 final val POLYtype = 169 final val TYPELAMBDAtype = 170 final val LAMBDAtpt = 171 @@ -518,7 +516,6 @@ object TastyFormat { | TYPEBOUNDStpt | ANNOTATEDtpt | ANDtpt - | ORtpt | BYNAMEtpt | MATCHtpt | BIND => true @@ -649,7 +646,6 @@ object TastyFormat { case ANDtype => "ANDtype" case ANDtpt => "ANDtpt" case ORtype => "ORtype" - case ORtpt => "ORtpt" case BYNAMEtype => "BYNAMEtype" case BYNAMEtpt => "BYNAMEtpt" case POLYtype => "POLYtype" diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 101a03b9eec5..b6ed70be4381 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -562,9 +562,6 @@ class TreePickler(pickler: TastyPickler) { case AndTypeTree(tp1, tp2) => writeByte(ANDtpt) withLength { pickleTree(tp1); pickleTree(tp2) } - case OrTypeTree(tp1, tp2) => - writeByte(ORtpt) - withLength { pickleTree(tp1); pickleTree(tp2) } case MatchTypeTree(bound, selector, cases) => writeByte(MATCHtpt) withLength { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 15660c4b22bc..daf15e8e9572 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -1181,8 +1181,6 @@ class TreeUnpickler(reader: TastyReader, val tpt2 = readTpt() // FIXME: We need to do this instead of "AndType(tpt1, tpt2)" to avoid self-type cyclic reference in tasty_tools untpd.AndTypeTree(tpt1, tpt2).withType(AndType(tpt1.tpe, tpt2.tpe)) - case ORtpt => - OrTypeTree(readTpt(), readTpt()) case ANNOTATEDtpt => Annotated(readTpt(), readTerm()) case LAMBDAtpt => diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 24e95eddb270..7d7fee5a1c14 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -504,9 +504,7 @@ object Parsers { val op = opInfo.operator val l = opInfo.operand val r = top - if (isType && !op.isBackquoted && op.name == tpnme.raw.BAR) { - OrTypeTree(l, r) - } else if (isType && !op.isBackquoted && op.name == tpnme.raw.AMP) { + if (isType && !op.isBackquoted && op.name == tpnme.raw.AMP) { AndTypeTree(l, r) } else InfixOp(l, op, r) diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index ca97ba0f0eef..244ebfd99c31 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -425,12 +425,13 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { toTextLocal(ref) ~ "." ~ keywordStr("type") case AndTypeTree(l, r) => changePrec(AndTypePrec) { toText(l) ~ " & " ~ atPrec(AndTypePrec + 1) { toText(r) } } - case OrTypeTree(l, r) => - changePrec(OrTypePrec) { toText(l) ~ " | " ~ atPrec(OrTypePrec + 1) { toText(r) } } case RefinedTypeTree(tpt, refines) => toTextLocal(tpt) ~ " " ~ blockText(refines) case AppliedTypeTree(tpt, args) => - toTextLocal(tpt) ~ "[" ~ Text(args map argText, ", ") ~ "]" + if (tpt.symbol == defn.orType && args.length == 2) + changePrec(OrTypePrec) { toText(args(0)) ~ " | " ~ atPrec(OrTypePrec + 1) { toText(args(1)) } } + else + toTextLocal(tpt) ~ "[" ~ Text(args map argText, ", ") ~ "]" case LambdaTypeTree(tparams, body) => changePrec(GlobalPrec) { tparamsText(tparams) ~ " -> " ~ toText(body) diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala index 0682c5c5bbfe..39083a7f1673 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala @@ -74,7 +74,6 @@ trait CoreImpl extends scala.tasty.reflect.Core { type Applied = tpd.AppliedTypeTree type Annotated = tpd.Annotated type And = tpd.AndTypeTree - type Or = tpd.OrTypeTree type MatchType = tpd.MatchTypeTree type ByName = tpd.ByNameTypeTree type LambdaTypeTree = tpd.LambdaTypeTree diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala index 34f7d45e7169..795ae20d3f9c 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala @@ -50,12 +50,7 @@ trait TypeOrBoundsTreesOpsImpl extends scala.tasty.reflect.TypeOrBoundsTreeOps w def annotation(implicit ctx: Contexts.Context): Term = x.annot } - def AndDeco(x: TypeTree.And): TypeTree.OrAPI = new TypeTree.OrAPI { - def left(implicit ctx: Contexts.Context): TypeTree = x.left - def right(implicit ctx: Contexts.Context): TypeTree = x.right - } - - def OrDeco(x: TypeTree.Or): TypeTree.OrAPI = new TypeTree.OrAPI { + def AndDeco(x: TypeTree.And): TypeTree.AndAPI = new TypeTree.AndAPI { def left(implicit ctx: Contexts.Context): TypeTree = x.left def right(implicit ctx: Contexts.Context): TypeTree = x.right } @@ -273,26 +268,6 @@ trait TypeOrBoundsTreesOpsImpl extends scala.tasty.reflect.TypeOrBoundsTreeOps w } } - object IsOr extends IsOrModule { - def unapply(tpt: TypeOrBoundsTree)(implicit ctx: Context): Option[Or] = tpt match { - case tpt: tpd.OrTypeTree => Some(tpt) - case _ => None - } - } - - object Or extends OrModule { - def apply(left: TypeTree, right: TypeTree)(implicit ctx: Context): Or = - withDefaultPos(ctx => tpd.OrTypeTree(left, right)(ctx)) - - def copy(original: Or)(left: TypeTree, right: TypeTree)(implicit ctx: Context): Or = - tpd.cpy.OrTypeTree(original)(left, right) - - def unapply(x: TypeTree)(implicit ctx: Context): Option[(TypeTree, TypeTree)] = x match { - case x: tpd.OrTypeTree => Some(x.left, x.right) - case _ => None - } - } - object IsMatchType extends IsMatchTypeModule { def unapply(tpt: TypeOrBoundsTree)(implicit ctx: Context): Option[MatchType] = tpt match { case tpt: tpd.MatchTypeTree => Some(tpt) diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 0ec7aa5217e5..f6c7f57c7eee 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -234,7 +234,6 @@ class TreeChecker extends Phase with SymTransformer { // case tree: TypeTree => // case tree: SingletonTypeTree => // case tree: AndTypeTree => - // case tree: OrTypeTree => // case tree: RefinedTypeTree => // case tree: AppliedTypeTree => // case tree: ByNameTypeTree => diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 3ce98ff1cca3..f4934a273a37 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -521,9 +521,6 @@ trait TypeAssigner { def assignType(tree: untpd.AndTypeTree, left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree = tree.withType(AndType(checkNoWildcard(left).tpe, checkNoWildcard(right).tpe)) - def assignType(tree: untpd.OrTypeTree, left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree = - tree.withType(OrType(checkNoWildcard(left).tpe, checkNoWildcard(right).tpe)) - /** Assign type of RefinedType. * Refinements are typed as if they were members of refinement class `refineCls`. */ @@ -542,9 +539,10 @@ trait TypeAssigner { def assignType(tree: untpd.AppliedTypeTree, tycon: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree = { assert(!hasNamedArg(args)) val tparams = tycon.tpe.typeParams - val ownType = + var ownType = if (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes) else wrongNumberOfTypeArgs(tycon.tpe, tparams, args, tree.sourcePos) + if (tycon.symbol == defn.andType || tycon.symbol == defn.orType) ownType = ownType.dealias tree.withType(ownType) } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index fd6df929d16f..f511d2d1c52e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1279,13 +1279,6 @@ class Typer extends Namer assignType(cpy.AndTypeTree(tree)(left1, right1), left1, right1) } - def typedOrTypeTree(tree: untpd.OrTypeTree)(implicit ctx: Context): OrTypeTree = track("typedOrTypeTree") { - val where = "in a union type" - val left1 = checkNotSingleton(checkSimpleKinded(typed(tree.left)), where) - val right1 = checkNotSingleton(checkSimpleKinded(typed(tree.right)), where) - assignType(cpy.OrTypeTree(tree)(left1, right1), left1, right1) - } - def typedRefinedTypeTree(tree: untpd.RefinedTypeTree)(implicit ctx: Context): RefinedTypeTree = track("typedRefinedTypeTree") { val tpt1 = if (tree.tpt.isEmpty) TypeTree(defn.ObjectType) else typedAheadType(tree.tpt) val refineClsDef = desugar.refinedTypeToClass(tpt1, tree.refinements).withSpan(tree.span) @@ -1365,9 +1358,15 @@ class Typer extends Namer case (tparam, _) => tparam.paramInfo.bounds } - val args2 = preCheckKinds(args1, paramBounds) - // check that arguments conform to bounds is done in phase PostTyper - assignType(cpy.AppliedTypeTree(tree)(tpt1, args2), tpt1, args2) + var checkedArgs = preCheckKinds(args1, paramBounds) + // check that arguments conform to bounds is done in phase PostTyper + if (tpt1.symbol == defn.andType) + checkedArgs = checkedArgs.mapconserve(arg => + checkSimpleKinded(checkNoWildcard(arg))) + else if (tpt1.symbol == defn.orType) + checkedArgs = checkedArgs.mapconserve(arg => + checkNotSingleton(checkSimpleKinded(checkNoWildcard(arg)), "in a union type")) + assignType(cpy.AppliedTypeTree(tree)(tpt1, checkedArgs), tpt1, checkedArgs) } } @@ -2005,7 +2004,6 @@ class Typer extends Namer case tree: untpd.TypeTree => typedTypeTree(tree, pt) case tree: untpd.SingletonTypeTree => typedSingletonTypeTree(tree) case tree: untpd.AndTypeTree => typedAndTypeTree(tree) - case tree: untpd.OrTypeTree => typedOrTypeTree(tree) case tree: untpd.RefinedTypeTree => typedRefinedTypeTree(tree) case tree: untpd.AppliedTypeTree => typedAppliedTypeTree(tree) case tree: untpd.LambdaTypeTree => typedLambdaTypeTree(tree)(ctx.localContext(tree, NoSymbol).setNewScope) diff --git a/library/src/scala/tasty/reflect/Printers.scala b/library/src/scala/tasty/reflect/Printers.scala index e24b5c0acc5a..4984b4b3c05e 100644 --- a/library/src/scala/tasty/reflect/Printers.scala +++ b/library/src/scala/tasty/reflect/Printers.scala @@ -219,8 +219,6 @@ trait Printers this += "TypeTree.Singleton(" += ref += ")" case TypeTree.And(left, right) => this += "TypeTree.And(" += left += ", " += right += ")" - case TypeTree.Or(left, right) => - this += "TypeTree.Or(" += left += ", " += right += ")" case TypeTree.Refined(tpt, refinements) => this += "TypeTree.Refined(" += tpt += ", " ++= refinements += ")" case TypeTree.Applied(tpt, args) => @@ -1423,12 +1421,12 @@ trait Printers printTypeTree(left) this += highlightTypeDef(" & ", color) printTypeTree(right) - +/* case TypeTree.Or(left, right) => printTypeTree(left) this += highlightTypeDef(" | ", color) printTypeTree(right) - +*/ case TypeTree.MatchType(bound, selector, cases) => printTypeTree(selector) this += highlightKeyword(" match ", color) diff --git a/library/src/scala/tasty/reflect/TreeUtils.scala b/library/src/scala/tasty/reflect/TreeUtils.scala index 36c0b5e2ca60..8c8448da4082 100644 --- a/library/src/scala/tasty/reflect/TreeUtils.scala +++ b/library/src/scala/tasty/reflect/TreeUtils.scala @@ -94,7 +94,6 @@ trait TreeUtils case TypeTree.Projection(qualifier, _) => foldTypeTree(x, qualifier) case TypeTree.Singleton(ref) => foldTree(x, ref) case TypeTree.And(left, right) => foldTypeTree(foldTypeTree(x, left), right) - case TypeTree.Or(left, right) => foldTypeTree(foldTypeTree(x, left), right) case TypeTree.Refined(tpt, refinements) => foldTrees(foldTypeTree(x, tpt), refinements) case TypeTree.Applied(tpt, args) => foldTypeTrees(foldTypeTree(x, tpt), args) case TypeTree.ByName(result) => foldTypeTree(x, result) @@ -256,8 +255,6 @@ trait TreeUtils TypeTree.Applied.copy(tree)(transformTypeTree(tree.tpt), transformTypeOrBoundsTrees(tree.args)) case TypeTree.IsAnd(tree) => TypeTree.And.copy(tree)(transformTypeTree(tree.left), transformTypeTree(tree.right)) - case TypeTree.IsOr(tree) => - TypeTree.Or.copy(tree)(transformTypeTree(tree.left), transformTypeTree(tree.right)) case TypeTree.IsMatchType(tree) => TypeTree.MatchType.copy(tree)(tree.bound.map(b => transformTypeTree(b)), transformTypeTree(tree.selector), transformTypeCaseDefs(tree.cases)) case TypeTree.IsByName(tree) => diff --git a/library/src/scala/tasty/reflect/TypeOrBoundsTreeOps.scala b/library/src/scala/tasty/reflect/TypeOrBoundsTreeOps.scala index 2d69c48a8929..f026e027fb36 100644 --- a/library/src/scala/tasty/reflect/TypeOrBoundsTreeOps.scala +++ b/library/src/scala/tasty/reflect/TypeOrBoundsTreeOps.scala @@ -14,8 +14,7 @@ trait TypeOrBoundsTreeOps extends Core { implicit def RefinedDeco(x: TypeTree.Refined): TypeTree.RefinedAPI implicit def AppliedDeco(x: TypeTree.Applied): TypeTree.AppliedAPI implicit def AnnotatedDeco(x: TypeTree.Annotated): TypeTree.AnnotatedAPI - implicit def AndDeco(x: TypeTree.And): TypeTree.OrAPI - implicit def OrDeco(x: TypeTree.Or): TypeTree.OrAPI + implicit def AndDeco(x: TypeTree.And): TypeTree.AndAPI implicit def MatchTypeTreeDeco(x: TypeTree.MatchType): TypeTree.MatchTypeAPI implicit def ByNameDeco(x: TypeTree.ByName): TypeTree.ByNameAPI implicit def LambdaTypeTreeDeco(x: TypeTree.LambdaTypeTree): TypeTree.LambdaTypeTreeAPI @@ -208,24 +207,6 @@ trait TypeOrBoundsTreeOps extends Core { def unapply(typeOrBoundsTree: TypeOrBoundsTree)(implicit ctx: Context): Option[(TypeTree, TypeTree)] } - val IsOr: IsOrModule - abstract class IsOrModule { - /** Matches any Or and returns it */ - def unapply(tpt: TypeOrBoundsTree)(implicit ctx: Context): Option[Or] - } - - trait OrAPI { - def left(implicit ctx: Context): TypeTree - def right(implicit ctx: Context): TypeTree - } - - val Or: OrModule - abstract class OrModule { - def apply(left: TypeTree, right: TypeTree)(implicit ctx: Context): Or - def copy(original: Or)(left: TypeTree, right: TypeTree)(implicit ctx: Context): Or - def unapply(typeOrBoundsTree: TypeOrBoundsTree)(implicit ctx: Context): Option[(TypeTree, TypeTree)] - } - val IsMatchType: IsMatchTypeModule abstract class IsMatchTypeModule { /** Matches any MatchType and returns it */ diff --git a/tests/neg/and-wildcard.scala b/tests/neg/and-wildcard.scala new file mode 100644 index 000000000000..c4cf7baaa10f --- /dev/null +++ b/tests/neg/and-wildcard.scala @@ -0,0 +1,6 @@ +object Test { + + type And[X, Y] = X & Y + + val x: And[_, _] = ??? // error: unreducible +} \ No newline at end of file From 4772b86045308eddf6a253c63516353344f74051 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 17 Feb 2019 14:24:15 +0100 Subject: [PATCH 05/14] Drop AndTypeTree --- .../dotty/tools/dotc/ast/DesugarEnums.scala | 4 +- .../src/dotty/tools/dotc/ast/TreeInfo.scala | 1 - compiler/src/dotty/tools/dotc/ast/Trees.scala | 15 - compiler/src/dotty/tools/dotc/ast/tpd.scala | 3 - compiler/src/dotty/tools/dotc/ast/untpd.scala | 4 +- .../tools/dotc/core/tasty/TastyFormat.scala | 4 - .../tools/dotc/core/tasty/TreePickler.scala | 3 - .../tools/dotc/core/tasty/TreeUnpickler.scala | 11 +- .../tools/dotc/parsing/JavaParsers.scala | 2 +- .../dotty/tools/dotc/parsing/Parsers.scala | 10 +- .../dotc/parsing/TreeBuilder.scala.unused | 535 ------------------ .../tools/dotc/printing/RefinedPrinter.scala | 4 +- .../tools/dotc/tastyreflect/CoreImpl.scala | 1 - .../TypeOrBoundsTreesOpsImpl.scala | 25 - .../tools/dotc/transform/PostTyper.scala | 14 +- .../tools/dotc/transform/TreeChecker.scala | 1 - .../dotty/tools/dotc/typer/TypeAssigner.scala | 12 +- .../src/dotty/tools/dotc/typer/Typer.scala | 7 - .../src/scala/tasty/reflect/Printers.scala | 6 +- .../src/scala/tasty/reflect/TreeUtils.scala | 3 - .../tasty/reflect/TypeOrBoundsTreeOps.scala | 19 - 21 files changed, 31 insertions(+), 653 deletions(-) delete mode 100644 compiler/src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index f909efff6ba3..8f4e065fbf79 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -154,7 +154,7 @@ object DesugarEnums { parentTypes.head match { case parent: RefTree if parent.name == enumClass.name => // need a widen method to compute correct type parameters for enum base class - val widenParamType = (appliedEnumRef /: parentTypes.tail)(AndTypeTree) + val widenParamType = (appliedEnumRef /: parentTypes.tail)(makeAndType) val widenParam = makeSyntheticParameter(tpt = widenParamType) val widenDef = DefDef( name = s"${cdef.name}$$to$$${enumClass.name}".toTermName, @@ -164,7 +164,7 @@ object DesugarEnums { rhs = Ident(widenParam.name)) (TypeTree(), widenDef :: Nil) case _ => - (parentTypes.reduceLeft(AndTypeTree), Nil) + (parentTypes.reduceLeft(makeAndType), Nil) } } diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index 40a04ba5e8e0..84f0bca83746 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -166,7 +166,6 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => /** can this type be a type pattern? */ def mayBeTypePat(tree: Tree): Boolean = unsplice(tree) match { - case AndTypeTree(tpt1, tpt2) => mayBeTypePat(tpt1) || mayBeTypePat(tpt2) case RefinedTypeTree(tpt, refinements) => mayBeTypePat(tpt) || refinements.exists(_.isInstanceOf[Bind]) case AppliedTypeTree(tpt, args) => mayBeTypePat(tpt) || args.exists(_.isInstanceOf[Bind]) case Select(tpt, _) => mayBeTypePat(tpt) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index ade76d9e00cd..5eda3d940bcc 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -626,12 +626,6 @@ object Trees { type ThisTree[-T >: Untyped] = SingletonTypeTree[T] } - /** left & right */ - case class AndTypeTree[-T >: Untyped] private[ast] (left: Tree[T], right: Tree[T])(implicit @constructorOnly src: SourceFile) - extends TypTree[T] { - type ThisTree[-T >: Untyped] = AndTypeTree[T] - } - /** tpt { refinements } */ case class RefinedTypeTree[-T >: Untyped] private[ast] (tpt: Tree[T], refinements: List[Tree[T]])(implicit @constructorOnly src: SourceFile) extends ProxyTree[T] with TypTree[T] { @@ -928,7 +922,6 @@ object Trees { type Inlined = Trees.Inlined[T] type TypeTree = Trees.TypeTree[T] type SingletonTypeTree = Trees.SingletonTypeTree[T] - type AndTypeTree = Trees.AndTypeTree[T] type RefinedTypeTree = Trees.RefinedTypeTree[T] type AppliedTypeTree = Trees.AppliedTypeTree[T] type LambdaTypeTree = Trees.LambdaTypeTree[T] @@ -1095,10 +1088,6 @@ object Trees { case tree: SingletonTypeTree if (ref eq tree.ref) => tree case _ => finalize(tree, untpd.SingletonTypeTree(ref)(sourceFile(tree))) } - def AndTypeTree(tree: Tree)(left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree = tree match { - case tree: AndTypeTree if (left eq tree.left) && (right eq tree.right) => tree - case _ => finalize(tree, untpd.AndTypeTree(left, right)(sourceFile(tree))) - } def RefinedTypeTree(tree: Tree)(tpt: Tree, refinements: List[Tree])(implicit ctx: Context): RefinedTypeTree = tree match { case tree: RefinedTypeTree if (tpt eq tree.tpt) && (refinements eq tree.refinements) => tree case _ => finalize(tree, untpd.RefinedTypeTree(tpt, refinements)(sourceFile(tree))) @@ -1260,8 +1249,6 @@ object Trees { tree case SingletonTypeTree(ref) => cpy.SingletonTypeTree(tree)(transform(ref)) - case AndTypeTree(left, right) => - cpy.AndTypeTree(tree)(transform(left), transform(right)) case RefinedTypeTree(tpt, refinements) => cpy.RefinedTypeTree(tree)(transform(tpt), transformSub(refinements)) case AppliedTypeTree(tpt, args) => @@ -1386,8 +1373,6 @@ object Trees { x case SingletonTypeTree(ref) => this(x, ref) - case AndTypeTree(left, right) => - this(this(x, left), right) case RefinedTypeTree(tpt, refinements) => this(this(x, tpt), refinements) case AppliedTypeTree(tpt, args) => diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 9479590ad01b..5672feb468b4 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -161,9 +161,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def SingletonTypeTree(ref: Tree)(implicit ctx: Context): SingletonTypeTree = ta.assignType(untpd.SingletonTypeTree(ref), ref) - def AndTypeTree(left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree = - ta.assignType(untpd.AndTypeTree(left, right), left, right) - def RefinedTypeTree(parent: Tree, refinements: List[Tree], refineCls: ClassSymbol)(implicit ctx: Context): Tree = ta.assignType(untpd.RefinedTypeTree(parent, refinements), parent, refinements, refineCls) diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index cb444d085019..00d0b9fbbcc9 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -309,7 +309,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def Inlined(call: tpd.Tree, bindings: List[MemberDef], expansion: Tree)(implicit src: SourceFile): Inlined = new Inlined(call, bindings, expansion) def TypeTree()(implicit src: SourceFile): TypeTree = new TypeTree() def SingletonTypeTree(ref: Tree)(implicit src: SourceFile): SingletonTypeTree = new SingletonTypeTree(ref) - def AndTypeTree(left: Tree, right: Tree)(implicit src: SourceFile): AndTypeTree = new AndTypeTree(left, right) def RefinedTypeTree(tpt: Tree, refinements: List[Tree])(implicit src: SourceFile): RefinedTypeTree = new RefinedTypeTree(tpt, refinements) def AppliedTypeTree(tpt: Tree, args: List[Tree])(implicit src: SourceFile): AppliedTypeTree = new AppliedTypeTree(tpt, args) def LambdaTypeTree(tparams: List[TypeDef], body: Tree)(implicit src: SourceFile): LambdaTypeTree = new LambdaTypeTree(tparams, body) @@ -402,6 +401,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case _ => Tuple(ts) } + def makeAndType(left: Tree, right: Tree)(implicit ctx: Context): AppliedTypeTree = + AppliedTypeTree(ref(defn.andType.typeRef), left :: right :: Nil) + def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers = EmptyModifiers)(implicit ctx: Context): ValDef = ValDef(pname, tpe, EmptyTree).withMods(mods | Param) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 561989682f64..9993568f88e0 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -106,7 +106,6 @@ Standard-Section: "ASTs" TopLevelStat* LAMBDAtpt Length TypeParam* body_Term TYPEBOUNDStpt Length low_Term high_Term? ANNOTATEDtpt Length underlying_Term fullAnnotation_Term - ANDtpt Length left_Term right_Term MATCHtpt Length bound_Term? sel_Term CaseDef* BYNAMEtpt underlying_Term SHAREDterm term_ASTRef @@ -418,7 +417,6 @@ object TastyFormat { final val TYPEBOUNDS = 163 final val TYPEBOUNDStpt = 164 final val ANDtype = 165 - final val ANDtpt = 166 final val ORtype = 167 final val POLYtype = 169 final val TYPELAMBDAtype = 170 @@ -515,7 +513,6 @@ object TastyFormat { | LAMBDAtpt | TYPEBOUNDStpt | ANNOTATEDtpt - | ANDtpt | BYNAMEtpt | MATCHtpt | BIND => true @@ -644,7 +641,6 @@ object TastyFormat { case TYPEBOUNDStpt => "TYPEBOUNDStpt" case TYPEALIAS => "TYPEALIAS" case ANDtype => "ANDtype" - case ANDtpt => "ANDtpt" case ORtype => "ORtype" case BYNAMEtype => "BYNAMEtype" case BYNAMEtpt => "BYNAMEtpt" diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index b6ed70be4381..1cbe5d3a9581 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -559,9 +559,6 @@ class TreePickler(pickler: TastyPickler) { case AppliedTypeTree(tycon, args) => writeByte(APPLIEDtpt) withLength { pickleTree(tycon); args.foreach(pickleTree) } - case AndTypeTree(tp1, tp2) => - writeByte(ANDtpt) - withLength { pickleTree(tp1); pickleTree(tp2) } case MatchTypeTree(bound, selector, cases) => writeByte(MATCHtpt) withLength { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index daf15e8e9572..052497dad583 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -1175,12 +1175,11 @@ class TreeUnpickler(reader: TastyReader, // types. This came up in #137 of collection strawman. val tycon = readTpt() val args = until(end)(readTpt()) - untpd.AppliedTypeTree(tycon, args).withType(tycon.tpe.safeAppliedTo(args.tpes)) - case ANDtpt => - val tpt1 = readTpt() - val tpt2 = readTpt() - // FIXME: We need to do this instead of "AndType(tpt1, tpt2)" to avoid self-type cyclic reference in tasty_tools - untpd.AndTypeTree(tpt1, tpt2).withType(AndType(tpt1.tpe, tpt2.tpe)) + val ownType = + if (tycon.symbol == defn.andType) AndType(args(0).tpe, args(1).tpe) + else if (tycon.symbol == defn.orType) OrType(args(0).tpe, args(1).tpe) + else tycon.tpe.safeAppliedTo(args.tpes) + untpd.AppliedTypeTree(tycon, args).withType(ownType) case ANNOTATEDtpt => Annotated(readTpt(), readTerm()) case LAMBDAtpt => diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala index 3803559d4d10..fedca67ec6f2 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -428,7 +428,7 @@ object JavaParsers { } val ts = buf.toList if (ts.tail.isEmpty) ts.head - else ts.reduce(AndTypeTree(_,_)) + else ts.reduce(makeAndType(_,_)) } def formalParams(): List[ValDef] = { diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 7d7fee5a1c14..bdd00d714f9d 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -501,13 +501,7 @@ object Parsers { opStack = opStack.tail recur { atSpan(opInfo.operator.span union opInfo.operand.span union top.span) { - val op = opInfo.operator - val l = opInfo.operand - val r = top - if (isType && !op.isBackquoted && op.name == tpnme.raw.AMP) { - AndTypeTree(l, r) - } else - InfixOp(l, op, r) + InfixOp(opInfo.operand, opInfo.operator, top) } } } @@ -909,7 +903,7 @@ object Parsers { if (ctx.settings.strict.value) deprecationWarning(DeprecatedWithOperator()) in.nextToken() - AndTypeTree(t, withType()) + makeAndType(t, withType()) } else t diff --git a/compiler/src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused b/compiler/src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused deleted file mode 100644 index d92cbd9572f1..000000000000 --- a/compiler/src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused +++ /dev/null @@ -1,535 +0,0 @@ -package dotty.tools -package dotc -package parsing - -import core._ -import Flags._, Trees._, TypedTrees._, UntypedTrees._, Names._, StdNames._, NameOps._, Contexts._ -import scala.collection.mutable.ListBuffer -import util.Spans._, Symbols._, Decorators._, Flags._, Constants._ -import TreeInfo._ - -/** Methods for building trees, used in the parser. All the trees - * returned by this class must be untyped. - * Note: currently unused - */ -class TreeBuilder(implicit ctx: Context) { - - import untpd._ - - def scalaDot(name: Name): Select = - Select(new TypedSplice(tpd.Ident(defn.ScalaPackageVal.termRef)), name) - - def scalaAnyRefConstr = scalaDot(tpnme.AnyRef) - def scalaAnyValConstr = scalaDot(tpnme.AnyVal) - def scalaAnyConstr = scalaDot(tpnme.Any) - def scalaUnitConstr = scalaDot(tpnme.Unit) - def productConstr = scalaDot(tpnme.Product) - def productConstrN(n: Int) = scalaDot(("Product" + n).toTypeName) - def serializableConstr = scalaDot(tpnme.Serializable) - - def convertToTypeName(t: Tree): Tree = ??? - - private implicit val cpos = NoPosition - - /** Convert all occurrences of (lower-case) variables in a pattern as follows: - * x becomes x @ _ - * x: T becomes x @ (_: T) - * Also covert all toplevel lower-case type arguments as follows: - * t becomes t @ _ - */ - private object patvarTransformer extends TreeTransformer { - override def transform(tree: Tree): Tree = tree match { - case Ident(name) if isVarPattern(tree) && name != nme.WILDCARD => - Bind( - name, Ident(nme.WILDCARD).withPos(tree.pos.focus) - ).withSpan(tree.span) - case Typed(id @ Ident(name), tpt) if isVarPattern(id) && name != nme.WILDCARD => - Bind( - name, - Typed( - Ident(nme.WILDCARD).withPos(tree.pos.focus), - transform(tpt) - ).withPos(tree.pos.withStart(tree.pos.point)) - ).withPos(tree.pos.withPoint(id.pos.point)) - case Apply(fn @ Apply(_, _), args) => - tree.derivedApply(transform(fn), transform(args)) - case Apply(fn, args) => - tree.derivedApply(fn, transform(args)) - case Typed(expr, tpt) => - tree.derivedTyped(transform(expr), transform(tpt)) - case Bind(name, body) => - tree.derivedBind(name, transform(body)) - case AppliedTypeTree(tycon, args) => - tree.derivedAppliedTypeTree(tycon, args map transform) - case Alternative(_) | Typed(_, _) | AndTypeTree(_, _) | Annotated(_, _) => - super.transform(tree) - case Parens(_) => - stripParens(tree) - case _ => - tree - } - } - - case class VariableInfo(name: Name, tree: Tree, pos: Position) - - /** Traverse pattern and collect all variable names with their types in buffer - * The variables keep their positions; whereas the pattern is converted to be - * synthetic for all nodes that contain a variable position. - */ - object getVars extends TreeAccumulator[ListBuffer[VariableInfo]] { - - def namePos(tree: Tree, name: Name): Position = - if (name contains '$') tree.pos.focus - else { - val start = tree.pos.start - val end = start + name.decode.length - Position(start, end) - } - - override def apply(buf: ListBuffer[VariableInfo], tree: Tree): ListBuffer[VariableInfo] = { - def seenName(name: Name) = buf exists (_.name == name) - def add(name: Name, t: Tree): ListBuffer[VariableInfo] = - if (seenName(name)) buf else buf += VariableInfo(name, t, namePos(tree, name)) - - tree match { - case Bind(nme.WILDCARD, _) => - foldOver(buf, tree) - case Bind(name, Typed(tree1, tpt)) if !mayBeTypePat(tpt) => - apply(add(name, tpt), tree1) - case Bind(name, tree1) => - apply(add(name, TypeTree()), tree1) - case _ => - foldOver(buf, tree) - } - } - } - - /** Returns list of all pattern variables, possibly with their types, - * without duplicates - */ - private def getVariables(tree: Tree): List[VariableInfo] = - getVars(new ListBuffer[VariableInfo], tree).toList - - def byNameApplication(tpe: Tree): Tree = - AppliedTypeTree(scalaDot(tpnme.BYNAME_PARAM_CLASS), List(tpe)) - def repeatedApplication(tpe: Tree): Tree = - AppliedTypeTree(scalaDot(tpnme.REPEATED_PARAM_CLASS), List(tpe)) - - def makeTuple(trees: List[Tree])(implicit cpos: Position): Tree = { - def mkPair(t1: Tree, t2: Tree) = { - if (t1.isType) AppliedTypeTree(scalaDot(tpnme.Pair), List(t1, t2)) - else Pair(t1, t2) - } - trees reduce mkPair - } - - def stripParens(t: Tree) = t match { - case Parens(t) => t - case _ => t - } - - def makeSelfDef(name: TermName, tpt: Tree): ValDef = - ValDef(Modifiers(Private), name, tpt, EmptyTree()) - - /** If tree is a variable pattern, return its variable info. - * Otherwise return none. - */ - private def matchVarPattern(tree: Tree): Option[VariableInfo] = { - def wildType(t: Tree): Option[Tree] = t match { - case Ident(x) if x.toTermName == nme.WILDCARD => Some(TypeTree()) - case Typed(Ident(x), tpt) if x.toTermName == nme.WILDCARD => Some(tpt) - case _ => None - } - tree match { - case Ident(name) => Some(VariableInfo(name, TypeTree(), tree.pos)) - case Bind(name, body) => wildType(body) map (x => VariableInfo(name, x, tree.pos)) - case Typed(id @ Ident(name), tpt) => Some(VariableInfo(name, tpt, id.pos)) - case _ => None - } - } - - /** Create tree representing (unencoded) binary operation expression or pattern. */ - def makeBinop(isExpr: Boolean, left: Tree, op: TermName, right: Tree, opPos: Position): Tree = { - def mkNamed(args: List[Tree]) = - if (isExpr) args map { - case arg @ Assign(Ident(name), rhs) => NamedArg(name, rhs).withPos(arg.pos) - case arg => arg - } else args - val arguments = right match { - case Parens(arg) => mkNamed(arg :: Nil) - case _ => right :: Nil - } - if (isExpr) { - if (isLeftAssoc(op)) { - Apply(Select(stripParens(left), op.encode).withPos(opPos), arguments) - } else { - val x = ctx.freshName().toTermName - Block( - List(ValDef(Modifiers(Synthetic), x, TypeTree(), stripParens(left))), - Apply(Select(stripParens(right), op.encode).withPos(opPos), List(Ident(x).withPos(left.pos)))) - } - } else { - Apply(Ident(op.encode).withPos(opPos), stripParens(left) :: arguments) - } - } - - /** tpt. */ - def SelectConstructor(tpt: Tree): Tree = - Select(tpt, nme.CONSTRUCTOR) - - private def splitArgss(constr: Tree, outerArgss: List[List[Tree]]): (Tree, List[List[Tree]]) = constr match { - case Apply(tree, args) => splitArgss(tree, args :: outerArgss) - case _ => (constr, if (outerArgss.isEmpty) ListOfNil else outerArgss) - } - - /** new tpt(argss_1)...(argss_n) - * @param npos the position spanning , without any arguments - */ - def makeNew(parentConstr: Tree) = { - val (tpt, argss) = splitArgss(parentConstr, Nil) - New(tpt, argss) - } - - /** Create positioned tree representing an object creation stats } - */ - def makeNew(templ: Template): Tree = { - val x = tpnme.ANON_CLASS - val nu = makeNew(Ident(x)) - val clsDef = { - implicit val cpos = NoPosition - ClassDef(Modifiers(Final), x, Nil, templ) - } - Block(clsDef, nu) - } - - /** Create positioned tree representing an object creation stats } - * @param cpos the position of the new, focus should be the first parent's start. - */ - def makeNew(parents: List[Tree], self: ValDef, stats: List[Tree]): Tree = { - val newPos = Position(cpos.start, cpos.point) - val clsPos = Position(cpos.point, cpos.end) - if (parents.isEmpty) - makeNew(List(scalaAnyRefConstr.withPos(newPos.endPos)), self, stats) - else if (parents.tail.isEmpty && stats.isEmpty) - makeNew(parents.head) - else { - val x = tpnme.ANON_CLASS - val nu = makeNew(Ident(x).withPos(newPos)).withPos(newPos) - val clsDef = { - implicit val cpos = clsPos - ClassDef(Modifiers(Final), x, Nil, Template(???, parents, self, stats)) - } - Block(clsDef, nu) - } - } - - /** Create a tree representing an assignment */ - def makeAssign(lhs: Tree, rhs: Tree): Tree = lhs match { - case Apply(fn, args) => - Apply(Select(fn, nme.update), args :+ rhs) - case _ => - Assign(lhs, rhs) - } - - /** A type tree corresponding to (possibly unary) intersection type - def makeIntersectionTypeTree(tps: List[Tree]): Tree = - if (tps.tail.isEmpty) tps.head - else CompoundTypeTree(Template(tps, emptyValDef, Nil))*/ - - private def labelDefAndCall(lname: TermName, rhs: Tree, call: Tree) = { - val ldef = DefDef(Modifiers(Label).withPos(cpos.startPos), lname, Nil, ListOfNil, TypeTree(), rhs) - Block(ldef, call) - } - - private def labelCall(lname: TermName): Apply = - Apply(Ident(lname), Nil) - - /** Create tree representing a while loop */ - def makeWhile(lname: TermName, cond: Tree, body: Tree): Tree = { - val continu = labelCall(lname).withPos((cond.pos union body.pos).endPos) - val rhs = { - implicit val cpos = NoPosition - If(cond, Block(body, continu), Literal(Constant()).withPos(continu.pos)) - } - labelDefAndCall(lname, rhs, continu) - } - - /** Create tree representing a do-while loop */ - def makeDoWhile(lname: TermName, body: Tree, cond: Tree): Tree = { - val continu = labelCall(lname).withPos((cond.pos union body.pos).endPos) - val rhs = Block(body, If(cond, continu, Literal(Constant()).withPos(continu.pos))) - labelDefAndCall(lname, rhs, continu) - } - - /** Create block of statements `stats` */ - def makeBlock(stats: List[Tree]): Tree = - if (stats.isEmpty) Literal(Constant()) - else if (!stats.last.isTerm) Block(stats, Literal(Constant()).withPos(cpos.endPos)) - else if (stats.length == 1) stats.head - else Block(stats.init, stats.last) - - def makePatFilter(tree: Tree, condition: Tree, canDrop: Boolean): Tree = { - val cases = List( - CaseDef(condition, EmptyTree(), Literal(Constant(true))), - CaseDef(Ident(nme.WILDCARD), EmptyTree(), Literal(Constant(false))) - ) - val matchTree = makeVisitor(cases, checkExhaustive = false, canDrop) - locally { - implicit val cpos = tree.pos - Apply(Select(tree, nme.withFilter), matchTree :: Nil) - } - } - - /** Create tree for for-comprehension generator or */ - def makeGenerator(pat: Tree, valeq: Boolean, rhs: Tree): Enumerator = { - val pat1 = patvarTransformer.transform(pat) - if (valeq) ValEq(pat1, rhs) - else ValFrom(pat1, makePatFilter(rhs, pat1, canDrop = true)) - } - -/* - def makeSyntheticTypeParam(pname: TypeName, bounds: Tree) = - TypeDef(Modifiers(DEFERRED | SYNTHETIC), pname, Nil, bounds) -*/ - abstract class Enumerator { def pos: Position } - case class ValFrom(pat: Tree, rhs: Tree) extends Enumerator { - val pos = cpos union pat.pos union rhs.pos - } - case class ValEq(pat: Tree, rhs: Tree) extends Enumerator { - val pos = cpos union pat.pos union rhs.pos - } - case class Filter(test: Tree) extends Enumerator { - val pos = cpos union test.pos - } - - /** Create tree for for-comprehension or - * where mapName and flatMapName are chosen - * corresponding to whether this is a for-do or a for-yield. - * The creation performs the following rewrite rules: - * - * 1. - * - * for (P <- G) E ==> G.foreach (P => E) - * - * Here and in the following (P => E) is interpreted as the function (P => E) - * if P is a variable pattern and as the partial function { case P => E } otherwise. - * - * 2. - * - * for (P <- G) yield E ==> G.map (P => E) - * - * 3. - * - * for (P_1 <- G_1; P_2 <- G_2; ...) ... - * ==> - * G_1.flatMap (P_1 => for (P_2 <- G_2; ...) ...) - * - * 4. - * - * for (P <- G; E; ...) ... - * => - * for (P <- G.filter (P => E); ...) ... - * - * 5. For any N: - * - * for (P_1 <- G; P_2 = E_2; val P_N = E_N; ...) - * ==> - * for (TupleN(P_1, P_2, ... P_N) <- - * for (x_1 @ P_1 <- G) yield { - * val x_2 @ P_2 = E_2 - * ... - * val x_N & P_N = E_N - * TupleN(x_1, ..., x_N) - * } ...) - * - * If any of the P_i are variable patterns, the corresponding `x_i @ P_i' is not generated - * and the variable constituting P_i is used instead of x_i - * - * @param mapName The name to be used for maps (either map or foreach) - * @param flatMapName The name to be used for flatMaps (either flatMap or foreach) - * @param enums The enumerators in the for expression - * @param body The body of the for expression - */ - private def makeFor(mapName: TermName, flatMapName: TermName, enums: List[Enumerator], body: Tree): Tree = { - - /** make a closure pat => body. - * The closure is assigned a transparent position with the point at pos.point and - * the limits given by pat and body. - */ - def makeClosure(pat: Tree, body: Tree): Tree = - matchVarPattern(pat) match { - case Some(VariableInfo(name, tpt, pos)) => - Function(ValDef(Modifiers(Param).withPos(cpos.startPos), name.toTermName, tpt, EmptyTree()).withPos(pos) :: Nil, body) - case None => - makeVisitor(List(CaseDef(pat, EmptyTree(), body)), checkExhaustive = false) - } - - /** Make an application qual.meth(pat => body) positioned at `pos`. - */ - def makeCombination(meth: TermName, qual: Tree, pat: Tree, body: Tree): Tree = - Apply(Select(qual, meth).withPos(NoPosition), makeClosure(pat, body)) - - /** Optionally, if pattern is a `Bind`, the bound name, otherwise None. - */ - def patternVar(pat: Tree): Option[Name] = pat match { - case Bind(name, _) => Some(name) - case _ => None - } - - /** If `pat` is not yet a `Bind` wrap it in one with a fresh name - */ - def makeBind(pat: Tree): Tree = pat match { - case Bind(_, _) => pat - case _ => Bind(ctx.freshName().toTermName, pat) - } - - /** A reference to the name bound in Bind `pat`. - */ - def makeValue(pat: Tree): Tree = pat match { - case Bind(name, _) => Ident(name).withPos(pat.pos.focus) - } - - enums match { - case (enum @ ValFrom(pat, rhs)) :: Nil => - makeCombination(mapName, rhs, pat, body).withPos(enum.pos) - case ValFrom(pat, rhs) :: (rest @ (ValFrom( _, _) :: _)) => - makeCombination(flatMapName, rhs, pat, - makeFor(mapName, flatMapName, rest, body)) - case (enum @ ValFrom(pat, rhs)) :: Filter(test) :: rest => - makeFor(mapName, flatMapName, - ValFrom(pat, makeCombination(nme.withFilter, rhs, pat, test)) :: rest, - body) - case (enum @ ValFrom(pat, rhs)) :: rest => - val (valeqs, rest1) = rest.span(_.isInstanceOf[ValEq]) - assert(!valeqs.isEmpty) - val pats = valeqs map { case ValEq(pat, _) => pat } - val rhss = valeqs map { case ValEq(_, rhs) => rhs } - val defpat1 = makeBind(pat) - val defpats = pats map makeBind - val pdefs = (defpats, rhss).zipped flatMap (makePatDef) - val ids = (defpat1 :: defpats) map makeValue - val rhs1 = makeForYield(ValFrom(defpat1, rhs) :: Nil, Block(pdefs, makeTuple(ids))) - val allpats = pat :: pats - val vfrom1 = ValFrom(makeTuple(allpats), rhs1) - makeFor(mapName, flatMapName, vfrom1 :: rest1, body) - case _ => - EmptyTree() //may happen for erroneous input - } - } - - /** Create tree for for-do comprehension */ - def makeFor(enums: List[Enumerator], body: Tree): Tree = - makeFor(nme.foreach, nme.foreach, enums, body) - - /** Create tree for for-yield comprehension */ - def makeForYield(enums: List[Enumerator], body: Tree): Tree = - makeFor(nme.map, nme.flatMap, enums, body) - - /** Create tree for a pattern alternative */ - def makeAlternative(ts: List[Tree]): Tree = Alternative(ts flatMap alternatives) - - def alternatives(t: Tree): List[Tree] = t match { - case Alternative(ts) => ts - case _ => List(t) - } - - def mkAnnotated(cls: Symbol, tree: Tree) = - Annotated(TypedSplice(tpd.New(cls.typeRef)), tree) - - /** Create visitor x match cases> */ - def makeVisitor(cases: List[CaseDef], checkExhaustive: Boolean, canDrop: Boolean = false): Tree = { - val x = ctx.freshName().toTermName - val id = Ident(x) - val sel = - if (canDrop) mkAnnotated(???, id) - else if (!checkExhaustive) mkAnnotated(defn.UncheckedAnnot, id) - else id - Function(List(ugen.syntheticParameter(x)), Match(sel, cases)) - } - - /** Create tree for case definition rhs> */ - def makeCaseDef(pat: Tree, guard: Tree, rhs: Tree): CaseDef = - CaseDef(patvarTransformer.transform(pat), guard, rhs) - - /** Create tree for pattern definition */ - def makePatDef(pat: Tree, rhs: Tree): List[Tree] = - makePatDef(Modifiers(), pat, rhs) - - /** Create tree for pattern definition */ - def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree, varsArePatterns: Boolean = false): List[Tree] = matchVarPattern(pat) match { - case Some(VariableInfo(name, tpt, pos)) if varsArePatterns => - ValDef(mods, name.toTermName, tpt, rhs).withPos(pos) :: Nil // point comes from pat.pos - - case _ => - // in case there is exactly one variable x_1 in pattern - // val/var p = e ==> val/var x_1 = e.match (case p => (x_1)) - // - // in case there are zero or more than one variables in pattern - // val/var p = e ==> private synthetic val t$ = e.match (case p => (x_1, ..., x_N)) - // val/var x_1 = t$._1 - // ... - // val/var x_N = t$._N - - val rhsUnchecked = mkAnnotated(defn.UncheckedAnnot, rhs) - - // TODO: clean this up -- there is too much information packed into makePatDef's `pat` argument - // when it's a simple identifier (case Some((name, tpt)) -- above), - // pat should have the type ascription that was specified by the user - // however, in `case None` (here), we must be careful not to generate illegal pattern trees (such as `(a, b): Tuple2[Int, String]`) - // i.e., this must hold: pat1 match { case Typed(expr, tp) => assert(expr.isInstanceOf[Ident]) case _ => } - // if we encounter such an erroneous pattern, we strip off the type ascription from pat and propagate the type information to rhs - val (pat1, rhs1) = patvarTransformer.transform(pat) match { - // move the Typed ascription to the rhs - case Typed(expr, tpt) if !expr.isInstanceOf[Ident] => - val rhsTypedUnchecked = - if (tpt.isEmpty) rhsUnchecked else Typed(rhsUnchecked, tpt) - (expr, rhsTypedUnchecked) - case ok => - (ok, rhsUnchecked) - } - val vars = getVariables(pat1) - val ids = vars map (v => Ident(v.name).withPos(v.pos)) - val caseDef = CaseDef(pat1, EmptyTree(), makeTuple(ids)) - val matchExpr = Match(rhs1, caseDef :: Nil) - vars match { - case List(VariableInfo(vname, tpt, pos)) => - ValDef(mods, vname.toTermName, tpt, matchExpr) :: Nil - case _ => - val tmpName = ctx.freshName().toTermName - val patMods = Modifiers(PrivateLocal | Synthetic | (mods.flags & Lazy)) - val firstDef = ValDef(patMods, tmpName, TypeTree(), matchExpr) - val restDefs = for { - (VariableInfo(vname, tpt, pos), n) <- vars.zipWithIndex - } yield { - val rhs = { - implicit val cpos = pos.focus - Select(Ident(tmpName), ("_" + n).toTermName) - } - ValDef(mods, vname.toTermName, tpt, rhs).withPos(pos) - } - firstDef :: restDefs - } - } - - /** Create a tree representing the function type (argtpes) => restpe */ - def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = - AppliedTypeTree(scalaDot(("Function" + argtpes.length).toTypeName), argtpes ::: List(restpe)) - - /** Append implicit parameter section if `contextBounds` nonempty */ - def addEvidenceParams(owner: Name, vparamss: List[List[ValDef]], contextBounds: List[Tree]): List[List[ValDef]] = { - if (contextBounds.isEmpty) vparamss - else { - val mods = Modifiers(if (owner.isTypeName) PrivateLocal | ParamAccessor else Param) - val evidenceParams = for (tpt <- contextBounds) yield { - val pname = ctx.freshName(nme.EVIDENCE_PARAM_PREFIX).toTermName - ValDef(mods | Implicit | Synthetic, pname, tpt, EmptyTree()) - } - vparamss.reverse match { - case (vparams @ (vparam :: _)) :: _ if vparam.mods is Implicit => - vparamss.init :+ (evidenceParams ++ vparams) - case _ => - vparamss :+ evidenceParams - } - } - } -} diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 244ebfd99c31..082b737c8d81 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -423,13 +423,13 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { typeText(toText(tree.typeOpt)) case SingletonTypeTree(ref) => toTextLocal(ref) ~ "." ~ keywordStr("type") - case AndTypeTree(l, r) => - changePrec(AndTypePrec) { toText(l) ~ " & " ~ atPrec(AndTypePrec + 1) { toText(r) } } case RefinedTypeTree(tpt, refines) => toTextLocal(tpt) ~ " " ~ blockText(refines) case AppliedTypeTree(tpt, args) => if (tpt.symbol == defn.orType && args.length == 2) changePrec(OrTypePrec) { toText(args(0)) ~ " | " ~ atPrec(OrTypePrec + 1) { toText(args(1)) } } + else if (tpt.symbol == defn.andType && args.length == 2) + changePrec(AndTypePrec) { toText(args(0)) ~ " & " ~ atPrec(AndTypePrec + 1) { toText(args(1)) } } else toTextLocal(tpt) ~ "[" ~ Text(args map argText, ", ") ~ "]" case LambdaTypeTree(tparams, body) => diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala index 39083a7f1673..b9d37c1e3647 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala @@ -73,7 +73,6 @@ trait CoreImpl extends scala.tasty.reflect.Core { type Refined = tpd.RefinedTypeTree type Applied = tpd.AppliedTypeTree type Annotated = tpd.Annotated - type And = tpd.AndTypeTree type MatchType = tpd.MatchTypeTree type ByName = tpd.ByNameTypeTree type LambdaTypeTree = tpd.LambdaTypeTree diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala index 795ae20d3f9c..7541f6d820be 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala @@ -50,11 +50,6 @@ trait TypeOrBoundsTreesOpsImpl extends scala.tasty.reflect.TypeOrBoundsTreeOps w def annotation(implicit ctx: Contexts.Context): Term = x.annot } - def AndDeco(x: TypeTree.And): TypeTree.AndAPI = new TypeTree.AndAPI { - def left(implicit ctx: Contexts.Context): TypeTree = x.left - def right(implicit ctx: Contexts.Context): TypeTree = x.right - } - def MatchTypeTreeDeco(x: TypeTree.MatchType): TypeTree.MatchTypeAPI = new TypeTree.MatchTypeAPI { def bound(implicit ctx: Contexts.Context): Option[TypeTree] = if (x.bound == tpd.EmptyTree) None else Some(x.bound) def selector(implicit ctx: Contexts.Context): TypeTree = x.selector @@ -248,26 +243,6 @@ trait TypeOrBoundsTreesOpsImpl extends scala.tasty.reflect.TypeOrBoundsTreeOps w } } - object IsAnd extends IsAndModule { - def unapply(tpt: TypeOrBoundsTree)(implicit ctx: Context): Option[And] = tpt match { - case tpt: tpd.AndTypeTree => Some(tpt) - case _ => None - } - } - - object And extends AndModule { - def apply(left: TypeTree, right: TypeTree)(implicit ctx: Context): And = - withDefaultPos(ctx => tpd.AndTypeTree(left, right)(ctx)) - - def copy(original: And)(left: TypeTree, right: TypeTree)(implicit ctx: Context): And = - tpd.cpy.AndTypeTree(original)(left, right) - - def unapply(x: TypeTree)(implicit ctx: Context): Option[(TypeTree, TypeTree)] = x match { - case x: tpd.AndTypeTree => Some(x.left, x.right) - case _ => None - } - } - object IsMatchType extends IsMatchTypeModule { def unapply(tpt: TypeOrBoundsTree)(implicit ctx: Context): Option[MatchType] = tpt match { case tpt: tpd.MatchTypeTree => Some(tpt) diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index aa8b003795e7..82d91b03eba3 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -280,7 +280,14 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case tree @ Annotated(annotated, annot) => cpy.Annotated(tree)(transform(annotated), transformAnnot(annot)) case tree: AppliedTypeTree => - Checking.checkAppliedType(tree, boundsCheck = !ctx.mode.is(Mode.Pattern)) + if (tree.tpt.symbol == defn.andType) + Checking.checkNonCyclicInherited(tree.tpe, tree.args.tpes, EmptyScope, tree.posd) + // Ideally, this should be done by Typer, but we run into cyclic references + // when trying to typecheck self types which are intersections. + else if (tree.tpt.symbol == defn.orType) + // nothing to do + else + Checking.checkAppliedType(tree, boundsCheck = !ctx.mode.is(Mode.Pattern)) super.transform(tree) case SingletonTypeTree(ref) => Checking.checkRealizable(ref.tpe, ref.posd) @@ -292,11 +299,6 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case tpe => tpe } ) - case tree: AndTypeTree => - // Ideally, this should be done by Typer, but we run into cyclic references - // when trying to typecheck self types which are intersections. - Checking.checkNonCyclicInherited(tree.tpe, tree.left.tpe :: tree.right.tpe :: Nil, EmptyScope, tree.posd) - super.transform(tree) case tree: LambdaTypeTree => VarianceChecker.checkLambda(tree) super.transform(tree) diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index f6c7f57c7eee..e4d71a68488a 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -233,7 +233,6 @@ class TreeChecker extends Phase with SymTransformer { elems.foreach(assertIdentNotJavaClass) // case tree: TypeTree => // case tree: SingletonTypeTree => - // case tree: AndTypeTree => // case tree: RefinedTypeTree => // case tree: AppliedTypeTree => // case tree: ByNameTypeTree => diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index f4934a273a37..f171440b73bd 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -518,9 +518,6 @@ trait TypeAssigner { def assignType(tree: untpd.SingletonTypeTree, ref: Tree)(implicit ctx: Context): SingletonTypeTree = tree.withType(ref.tpe) - def assignType(tree: untpd.AndTypeTree, left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree = - tree.withType(AndType(checkNoWildcard(left).tpe, checkNoWildcard(right).tpe)) - /** Assign type of RefinedType. * Refinements are typed as if they were members of refinement class `refineCls`. */ @@ -539,10 +536,13 @@ trait TypeAssigner { def assignType(tree: untpd.AppliedTypeTree, tycon: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree = { assert(!hasNamedArg(args)) val tparams = tycon.tpe.typeParams - var ownType = - if (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes) + val ownType = + if (sameLength(tparams, args)) { + if (tycon.symbol == defn.andType) AndType(args(0).tpe, args(1).tpe) + else if (tycon.symbol == defn.orType) OrType(args(0).tpe, args(1).tpe) + else tycon.tpe.appliedTo(args.tpes) + } else wrongNumberOfTypeArgs(tycon.tpe, tparams, args, tree.sourcePos) - if (tycon.symbol == defn.andType || tycon.symbol == defn.orType) ownType = ownType.dealias tree.withType(ownType) } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index f511d2d1c52e..f7854d671c3e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1273,12 +1273,6 @@ class Typer extends Namer assignType(cpy.SingletonTypeTree(tree)(ref1), ref1) } - def typedAndTypeTree(tree: untpd.AndTypeTree)(implicit ctx: Context): AndTypeTree = track("typedAndTypeTree") { - val left1 = checkSimpleKinded(typed(tree.left)) - val right1 = checkSimpleKinded(typed(tree.right)) - assignType(cpy.AndTypeTree(tree)(left1, right1), left1, right1) - } - def typedRefinedTypeTree(tree: untpd.RefinedTypeTree)(implicit ctx: Context): RefinedTypeTree = track("typedRefinedTypeTree") { val tpt1 = if (tree.tpt.isEmpty) TypeTree(defn.ObjectType) else typedAheadType(tree.tpt) val refineClsDef = desugar.refinedTypeToClass(tpt1, tree.refinements).withSpan(tree.span) @@ -2003,7 +1997,6 @@ class Typer extends Namer case tree: untpd.Inlined => typedInlined(tree, pt) case tree: untpd.TypeTree => typedTypeTree(tree, pt) case tree: untpd.SingletonTypeTree => typedSingletonTypeTree(tree) - case tree: untpd.AndTypeTree => typedAndTypeTree(tree) case tree: untpd.RefinedTypeTree => typedRefinedTypeTree(tree) case tree: untpd.AppliedTypeTree => typedAppliedTypeTree(tree) case tree: untpd.LambdaTypeTree => typedLambdaTypeTree(tree)(ctx.localContext(tree, NoSymbol).setNewScope) diff --git a/library/src/scala/tasty/reflect/Printers.scala b/library/src/scala/tasty/reflect/Printers.scala index 4984b4b3c05e..845523d9ea33 100644 --- a/library/src/scala/tasty/reflect/Printers.scala +++ b/library/src/scala/tasty/reflect/Printers.scala @@ -217,8 +217,6 @@ trait Printers this += "TypeTree.Projection(" += qualifier += ", \"" += name += "\")" case TypeTree.Singleton(ref) => this += "TypeTree.Singleton(" += ref += ")" - case TypeTree.And(left, right) => - this += "TypeTree.And(" += left += ", " += right += ")" case TypeTree.Refined(tpt, refinements) => this += "TypeTree.Refined(" += tpt += ", " ++= refinements += ")" case TypeTree.Applied(tpt, args) => @@ -1416,12 +1414,12 @@ trait Printers this += " " printAnnotation(annot) } - +/* case TypeTree.And(left, right) => printTypeTree(left) this += highlightTypeDef(" & ", color) printTypeTree(right) -/* + case TypeTree.Or(left, right) => printTypeTree(left) this += highlightTypeDef(" | ", color) diff --git a/library/src/scala/tasty/reflect/TreeUtils.scala b/library/src/scala/tasty/reflect/TreeUtils.scala index 8c8448da4082..3463c8da8d51 100644 --- a/library/src/scala/tasty/reflect/TreeUtils.scala +++ b/library/src/scala/tasty/reflect/TreeUtils.scala @@ -93,7 +93,6 @@ trait TreeUtils case TypeTree.Select(qualifier, _) => foldTree(x, qualifier) case TypeTree.Projection(qualifier, _) => foldTypeTree(x, qualifier) case TypeTree.Singleton(ref) => foldTree(x, ref) - case TypeTree.And(left, right) => foldTypeTree(foldTypeTree(x, left), right) case TypeTree.Refined(tpt, refinements) => foldTrees(foldTypeTree(x, tpt), refinements) case TypeTree.Applied(tpt, args) => foldTypeTrees(foldTypeTree(x, tpt), args) case TypeTree.ByName(result) => foldTypeTree(x, result) @@ -253,8 +252,6 @@ trait TreeUtils TypeTree.Refined.copy(tree)(transformTypeTree(tree.tpt), transformTrees(tree.refinements).asInstanceOf[List[Definition]]) case TypeTree.IsApplied(tree) => TypeTree.Applied.copy(tree)(transformTypeTree(tree.tpt), transformTypeOrBoundsTrees(tree.args)) - case TypeTree.IsAnd(tree) => - TypeTree.And.copy(tree)(transformTypeTree(tree.left), transformTypeTree(tree.right)) case TypeTree.IsMatchType(tree) => TypeTree.MatchType.copy(tree)(tree.bound.map(b => transformTypeTree(b)), transformTypeTree(tree.selector), transformTypeCaseDefs(tree.cases)) case TypeTree.IsByName(tree) => diff --git a/library/src/scala/tasty/reflect/TypeOrBoundsTreeOps.scala b/library/src/scala/tasty/reflect/TypeOrBoundsTreeOps.scala index f026e027fb36..35a1d8125080 100644 --- a/library/src/scala/tasty/reflect/TypeOrBoundsTreeOps.scala +++ b/library/src/scala/tasty/reflect/TypeOrBoundsTreeOps.scala @@ -14,7 +14,6 @@ trait TypeOrBoundsTreeOps extends Core { implicit def RefinedDeco(x: TypeTree.Refined): TypeTree.RefinedAPI implicit def AppliedDeco(x: TypeTree.Applied): TypeTree.AppliedAPI implicit def AnnotatedDeco(x: TypeTree.Annotated): TypeTree.AnnotatedAPI - implicit def AndDeco(x: TypeTree.And): TypeTree.AndAPI implicit def MatchTypeTreeDeco(x: TypeTree.MatchType): TypeTree.MatchTypeAPI implicit def ByNameDeco(x: TypeTree.ByName): TypeTree.ByNameAPI implicit def LambdaTypeTreeDeco(x: TypeTree.LambdaTypeTree): TypeTree.LambdaTypeTreeAPI @@ -189,24 +188,6 @@ trait TypeOrBoundsTreeOps extends Core { def unapply(typeOrBoundsTree: TypeOrBoundsTree)(implicit ctx: Context): Option[(TypeTree, Term)] } - val IsAnd: IsAndModule - abstract class IsAndModule { - /** Matches any And and returns it */ - def unapply(tpt: TypeOrBoundsTree)(implicit ctx: Context): Option[And] - } - - trait AndAPI { - def left(implicit ctx: Context): TypeTree - def right(implicit ctx: Context): TypeTree - } - - val And: AndModule - abstract class AndModule { - def apply(left: TypeTree, right: TypeTree)(implicit ctx: Context): And - def copy(original: And)(left: TypeTree, right: TypeTree)(implicit ctx: Context): And - def unapply(typeOrBoundsTree: TypeOrBoundsTree)(implicit ctx: Context): Option[(TypeTree, TypeTree)] - } - val IsMatchType: IsMatchTypeModule abstract class IsMatchTypeModule { /** Matches any MatchType and returns it */ From 2499e0e1479723aebdc3dbd177bc394f1378ef49 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 17 Feb 2019 14:44:00 +0100 Subject: [PATCH 06/14] Disable tasty-extractors-2 test I believe the test is counter-productive. It leads to ossification by pedantically insisting on the status quo. If we want to test tasty extractors we need to find a way that tests it so that we can still change constrructors and extractors. --- tests/{ => disabled}/run/tasty-extractors-2/quoted_1.scala | 0 tests/{ => disabled}/run/tasty-extractors-2/quoted_2.scala | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/{ => disabled}/run/tasty-extractors-2/quoted_1.scala (100%) rename tests/{ => disabled}/run/tasty-extractors-2/quoted_2.scala (100%) diff --git a/tests/run/tasty-extractors-2/quoted_1.scala b/tests/disabled/run/tasty-extractors-2/quoted_1.scala similarity index 100% rename from tests/run/tasty-extractors-2/quoted_1.scala rename to tests/disabled/run/tasty-extractors-2/quoted_1.scala diff --git a/tests/run/tasty-extractors-2/quoted_2.scala b/tests/disabled/run/tasty-extractors-2/quoted_2.scala similarity index 100% rename from tests/run/tasty-extractors-2/quoted_2.scala rename to tests/disabled/run/tasty-extractors-2/quoted_2.scala From 7306b74f962e2fb0df2ae74734ad599993c10556 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 17 Feb 2019 15:05:12 +0100 Subject: [PATCH 07/14] Fix typo --- compiler/src/dotty/tools/dotc/transform/PostTyper.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 82d91b03eba3..5a21cf20c59f 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -285,7 +285,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase // Ideally, this should be done by Typer, but we run into cyclic references // when trying to typecheck self types which are intersections. else if (tree.tpt.symbol == defn.orType) - // nothing to do + () // nothing to do else Checking.checkAppliedType(tree, boundsCheck = !ctx.mode.is(Mode.Pattern)) super.transform(tree) From f47e8954abbb9dcaaf81e1351433e77b997f2144 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 17 Feb 2019 15:40:57 +0100 Subject: [PATCH 08/14] Fix syntax highlighting test --- .../dotty/tools/dotc/printing/SyntaxHighlightingTests.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/test/dotty/tools/dotc/printing/SyntaxHighlightingTests.scala b/compiler/test/dotty/tools/dotc/printing/SyntaxHighlightingTests.scala index 8bff254e663d..b60415205bba 100644 --- a/compiler/test/dotty/tools/dotc/printing/SyntaxHighlightingTests.scala +++ b/compiler/test/dotty/tools/dotc/printing/SyntaxHighlightingTests.scala @@ -39,8 +39,8 @@ class SyntaxHighlightingTests extends DottyTest { test("type Foo", " ") test("type Foo =", " =") test("type Foo = Int", " = ") - test("type A = String | Int", " = ") - test("type B = String & Int", " = ") + test("type A = String | Int", " = ") + test("type B = String & Int", " = ") } @Test From b9b9388b1441d0e27f1ef1f0f5e4970fda08dc63 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 18 Feb 2019 12:39:21 +0100 Subject: [PATCH 09/14] Drop mayBeTypePat It does not seem to serve a purpose. The only test where it was used does not really make sense. --- compiler/src/dotty/tools/dotc/ast/Desugar.scala | 2 +- compiler/src/dotty/tools/dotc/ast/TreeInfo.scala | 9 --------- tests/neg/patvars.scala | 12 ++++++++++++ 3 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 tests/neg/patvars.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 5b6abfabfaec..516028ec9f1f 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -1440,7 +1440,7 @@ object desugar { def collect(tree: Tree): Unit = tree match { case Bind(nme.WILDCARD, tree1) => collect(tree1) - case tree @ Bind(_, Typed(tree1, tpt)) if !mayBeTypePat(tpt) => + case tree @ Bind(_, Typed(tree1, tpt)) => add(tree, tpt) collect(tree1) case tree @ Bind(_, tree1) => diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index 84f0bca83746..fe3f1e2d8c2a 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -164,15 +164,6 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => /** Is name a left-associative operator? */ def isLeftAssoc(operator: Name): Boolean = !operator.isEmpty && (operator.toSimpleName.last != ':') - /** can this type be a type pattern? */ - def mayBeTypePat(tree: Tree): Boolean = unsplice(tree) match { - case RefinedTypeTree(tpt, refinements) => mayBeTypePat(tpt) || refinements.exists(_.isInstanceOf[Bind]) - case AppliedTypeTree(tpt, args) => mayBeTypePat(tpt) || args.exists(_.isInstanceOf[Bind]) - case Select(tpt, _) => mayBeTypePat(tpt) - case Annotated(tpt, _) => mayBeTypePat(tpt) - case _ => false - } - /** Is this argument node of the form : _*, or is it a reference to * such an argument ? The latter case can happen when an argument is lifted. */ diff --git a/tests/neg/patvars.scala b/tests/neg/patvars.scala new file mode 100644 index 000000000000..f0e2cd3da4ae --- /dev/null +++ b/tests/neg/patvars.scala @@ -0,0 +1,12 @@ +object Test { + + (??? : Any) match { + + case x1 | y1 => ??? // error // error + + case _: List[t2] | y2 => ??? // error // error + + case x3: Int | y3: String => ??? // error // error + + } +} \ No newline at end of file From b90230653718fc2e4f3de0b4875695de5bd1fe0f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 18 Feb 2019 12:40:51 +0100 Subject: [PATCH 10/14] Bump Tasty version --- compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 9993568f88e0..e853ded1ad13 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -244,7 +244,7 @@ Standard Section: "Comments" Comment* object TastyFormat { final val header: Array[Int] = Array(0x5C, 0xA1, 0xAB, 0x1F) - val MajorVersion: Int = 12 + val MajorVersion: Int = 13 val MinorVersion: Int = 0 /** Tags used to serialize names */ From 46f39d0a2bbd0260858f4930f243cef202d04a3c Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 18 Feb 2019 14:31:40 +0100 Subject: [PATCH 11/14] Remove And and Or from tasty.reflect.Core --- docs/docs/reference/other-new-features/tasty-reflect.md | 2 -- library/src/scala/tasty/reflect/Core.scala | 8 -------- 2 files changed, 10 deletions(-) diff --git a/docs/docs/reference/other-new-features/tasty-reflect.md b/docs/docs/reference/other-new-features/tasty-reflect.md index f2628371a541..1f85e824199f 100644 --- a/docs/docs/reference/other-new-features/tasty-reflect.md +++ b/docs/docs/reference/other-new-features/tasty-reflect.md @@ -124,8 +124,6 @@ TASTy Reflect provides the following types: +- TypeOrBoundsTree ---+ +- Refined | +- Applied | +- Annotated - | +- And - | +- Or | +- MatchType | +- ByName | +- LambdaTypeTree diff --git a/library/src/scala/tasty/reflect/Core.scala b/library/src/scala/tasty/reflect/Core.scala index c77e306144f5..c86a1e0447f6 100644 --- a/library/src/scala/tasty/reflect/Core.scala +++ b/library/src/scala/tasty/reflect/Core.scala @@ -45,8 +45,6 @@ package scala.tasty.reflect * +- TypeOrBoundsTree ---+ +- Refined * | +- Applied * | +- Annotated - * | +- And - * | +- Or * | +- MatchType * | +- ByName * | +- LambdaTypeTree @@ -295,12 +293,6 @@ trait Core { /** Type tree representing an annotated type */ type Annotated <: TypeTree - /** Type tree representing an intersection type */ - type And <: TypeTree - - /** Type tree representing a union type */ - type Or <: TypeTree - /** Type tree representing a type match */ type MatchType <: TypeTree From ec65323d33a4da1a1b097f716af00181e0955e0b Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 18 Feb 2019 14:32:58 +0100 Subject: [PATCH 12/14] Remove commented code --- library/src/scala/tasty/reflect/Printers.scala | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/library/src/scala/tasty/reflect/Printers.scala b/library/src/scala/tasty/reflect/Printers.scala index 845523d9ea33..ce3128c8b07b 100644 --- a/library/src/scala/tasty/reflect/Printers.scala +++ b/library/src/scala/tasty/reflect/Printers.scala @@ -1414,17 +1414,7 @@ trait Printers this += " " printAnnotation(annot) } -/* - case TypeTree.And(left, right) => - printTypeTree(left) - this += highlightTypeDef(" & ", color) - printTypeTree(right) - case TypeTree.Or(left, right) => - printTypeTree(left) - this += highlightTypeDef(" | ", color) - printTypeTree(right) -*/ case TypeTree.MatchType(bound, selector, cases) => printTypeTree(selector) this += highlightKeyword(" match ", color) From c14cf7ea9e288e9053d7ae98a721e521be927bf3 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 18 Feb 2019 14:43:58 +0100 Subject: [PATCH 13/14] Update checkfile and re-enable test --- tests/run/tasty-extractors-2.check | 4 ++-- tests/{disabled => }/run/tasty-extractors-2/quoted_1.scala | 0 tests/{disabled => }/run/tasty-extractors-2/quoted_2.scala | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename tests/{disabled => }/run/tasty-extractors-2/quoted_1.scala (100%) rename tests/{disabled => }/run/tasty-extractors-2/quoted_2.scala (100%) diff --git a/tests/run/tasty-extractors-2.check b/tests/run/tasty-extractors-2.check index 68b0372d7d9e..2f98f387de8a 100644 --- a/tests/run/tasty-extractors-2.check +++ b/tests/run/tasty-extractors-2.check @@ -16,10 +16,10 @@ Type.SymRef(IsClassSymbol(), Type.SymRef(IsPackageSymbol(), Ty Term.Inlined(None, Nil, Term.Typed(Term.Ident("Nil"), TypeTree.Applied(TypeTree.Ident("List"), List(TypeTree.Ident("Int"))))) Type.AppliedType(Type.SymRef(IsClassSymbol(), Type.ThisType(Type.SymRef(IsPackageSymbol(), NoPrefix()))), List(Type.SymRef(IsClassSymbol(), Type.SymRef(IsPackageSymbol(), Type.ThisType(Type.SymRef(IsPackageSymbol(<>), NoPrefix())))))) -Term.Inlined(None, Nil, Term.Typed(Term.Apply(Term.Select(Term.New(TypeTree.Ident("Baz")), ""), Nil), TypeTree.And(TypeTree.Ident("Foo"), TypeTree.Ident("Bar")))) +Term.Inlined(None, Nil, Term.Typed(Term.Apply(Term.Select(Term.New(TypeTree.Ident("Baz")), ""), Nil), TypeTree.Applied(TypeTree.Ident("&"), List(TypeTree.Ident("Foo"), TypeTree.Ident("Bar"))))) Type.AndType(Type.SymRef(IsClassSymbol(), Type.ThisType(Type.SymRef(IsPackageSymbol(<>), NoPrefix()))), Type.SymRef(IsClassSymbol(), Type.ThisType(Type.SymRef(IsPackageSymbol(<>), NoPrefix())))) -Term.Inlined(None, Nil, Term.Typed(Term.Literal(Constant.Int(1)), TypeTree.Or(TypeTree.Ident("Int"), TypeTree.Ident("String")))) +Term.Inlined(None, Nil, Term.Typed(Term.Literal(Constant.Int(1)), TypeTree.Applied(TypeTree.Ident("|"), List(TypeTree.Ident("Int"), TypeTree.Ident("String"))))) Type.OrType(Type.SymRef(IsClassSymbol(), Type.SymRef(IsPackageSymbol(), Type.ThisType(Type.SymRef(IsPackageSymbol(<>), NoPrefix())))), Type.SymRef(IsTypeSymbol(), Type.SymRef(IsValSymbol(), Type.ThisType(Type.SymRef(IsPackageSymbol(), NoPrefix()))))) Term.Inlined(None, Nil, Term.Block(List(ClassDef("Foo", DefDef("", Nil, List(Nil), TypeTree.Inferred(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Inferred()), ""), Nil)), Nil, None, Nil)), Term.Literal(Constant.Unit()))) diff --git a/tests/disabled/run/tasty-extractors-2/quoted_1.scala b/tests/run/tasty-extractors-2/quoted_1.scala similarity index 100% rename from tests/disabled/run/tasty-extractors-2/quoted_1.scala rename to tests/run/tasty-extractors-2/quoted_1.scala diff --git a/tests/disabled/run/tasty-extractors-2/quoted_2.scala b/tests/run/tasty-extractors-2/quoted_2.scala similarity index 100% rename from tests/disabled/run/tasty-extractors-2/quoted_2.scala rename to tests/run/tasty-extractors-2/quoted_2.scala From 6ad1432b213836e891ab957c87460af088bf4c8a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 18 Feb 2019 17:24:27 +0100 Subject: [PATCH 14/14] Add pending test --- tests/pending/pos/i4987.scala | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/pending/pos/i4987.scala diff --git a/tests/pending/pos/i4987.scala b/tests/pending/pos/i4987.scala new file mode 100644 index 000000000000..e251c4091697 --- /dev/null +++ b/tests/pending/pos/i4987.scala @@ -0,0 +1,18 @@ +object Foo { + + class Expr[T] + + abstract class Liftable[T] { + def toExpr(x: T): Expr[T] + } + + implicit class LiftExprOps[T](val x: T) extends AnyVal { + def toExpr(implicit ev: Liftable[T]): Expr[T] = ev.toExpr(x) + } + + implicit def NilIsLiftable: Liftable[Nil.type] = ??? + + Nil.toExpr(NilIsLiftable) + (Nil.toExpr: Expr[Nil.type]) + Nil.toExpr +} \ No newline at end of file