From 5b3d81be41725bceafdb44919219e8cbf4ba852a Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Tue, 1 May 2018 14:45:24 +0200 Subject: [PATCH 01/11] Produce AndTypeTree and OrTypeTree directly in Parsers, not Desugar Essentially reviewed in #4424. --- .../src/dotty/tools/dotc/ast/Desugar.scala | 4 +--- .../src/dotty/tools/dotc/parsing/Parsers.scala | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index e5021e5b955e..0ae11faf502b 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -1130,9 +1130,7 @@ object desugar { Apply(Select(Apply(Ident(nme.StringContext), strs), id), elems) case InfixOp(l, op, r) => if (ctx.mode is Mode.Type) - if (!op.isBackquoted && op.name == tpnme.raw.AMP) AndTypeTree(l, r) // l & r - else if (!op.isBackquoted && op.name == tpnme.raw.BAR) OrTypeTree(l, r) // l | r - else AppliedTypeTree(op, l :: r :: Nil) // op[l, r] + AppliedTypeTree(op, l :: r :: Nil) // op[l, r] else { assert(ctx.mode is Mode.Pattern) // expressions are handled separately by `binop` Apply(op, l :: r :: Nil) // op(l, r) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index edaf6850d8cf..806c8772c8bd 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -452,7 +452,7 @@ object Parsers { if (isLeftAssoc(op1) != op2LeftAssoc) syntaxError(MixedLeftAndRightAssociativeOps(op1, op2, op2LeftAssoc), offset) - def reduceStack(base: List[OpInfo], top: Tree, prec: Int, leftAssoc: Boolean, op2: Name): Tree = { + def reduceStack(base: List[OpInfo], top: Tree, prec: Int, leftAssoc: Boolean, op2: Name, isType: Boolean): Tree = { if (opStack != base && precedence(opStack.head.operator.name) == prec) checkAssoc(opStack.head.offset, opStack.head.operator.name, op2, leftAssoc) def recur(top: Tree): Tree = { @@ -464,7 +464,15 @@ object Parsers { opStack = opStack.tail recur { atPos(opInfo.operator.pos union opInfo.operand.pos union top.pos) { - InfixOp(opInfo.operand, opInfo.operator, top) + 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) { + AndTypeTree(l, r) + } else + InfixOp(l, op, r) } } } @@ -488,20 +496,20 @@ object Parsers { var top = first while (isIdent && isOperator) { val op = if (isType) typeIdent() else termIdent() - top = reduceStack(base, top, precedence(op.name), isLeftAssoc(op.name), op.name) + top = reduceStack(base, top, precedence(op.name), isLeftAssoc(op.name), op.name, isType) opStack = OpInfo(top, op, in.offset) :: opStack newLineOptWhenFollowing(canStartOperand) if (maybePostfix && !canStartOperand(in.token)) { val topInfo = opStack.head opStack = opStack.tail - val od = reduceStack(base, topInfo.operand, 0, true, in.name) + val od = reduceStack(base, topInfo.operand, 0, true, in.name, isType) return atPos(startOffset(od), topInfo.offset) { PostfixOp(od, topInfo.operator) } } top = operand() } - reduceStack(base, top, 0, true, in.name) + reduceStack(base, top, 0, true, in.name, isType) } /* -------- IDENTIFIERS AND LITERALS ------------------------------------------- */ From 9177c151ea9b911b21197caaabb4fb9196c78ab8 Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Mon, 30 Apr 2018 12:35:39 +0200 Subject: [PATCH 02/11] Refactor parser code that rejects forbidden wildcards The new API is required for all use cases in this PR. --- .../dotty/tools/dotc/parsing/Parsers.scala | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 806c8772c8bd..6c38aa2bba22 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -717,15 +717,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 = { - val t = typ() - findWildcardType(t) match { - case Some(wildcardPos) => - syntaxError(UnboundWildcardType(), wildcardPos) - scalaAny - case None => t - } - } + def toplevelTyp(): Tree = checkWildcard(typ()) /** Type ::= [FunArgMods] FunArgTypes `=>' Type * | HkTypeParamClause `->' Type @@ -925,7 +917,7 @@ object Parsers { else Nil first :: rest } - def typParser() = if (wildOK) typ() else toplevelTyp() + def typParser() = checkWildcard(typ(), wildOK) if (namedOK && in.token == IDENTIFIER) typParser() match { case Ident(name) if in.token == EQUALS => @@ -1020,6 +1012,17 @@ object Parsers { case _ => None } + def rejectWildcard(t: Tree, report: Position => Unit, fallbackTree: Tree): Tree = + findWildcardType(t) match { + case Some(wildcardPos) => + report(wildcardPos) + fallbackTree + case None => t + } + + def checkWildcard(t: Tree, wildOK: Boolean = false, fallbackTree: Tree = scalaAny): Tree = + if (wildOK) t else rejectWildcard(t, syntaxError(UnboundWildcardType(), _), fallbackTree) + /* ----------- EXPRESSIONS ------------------------------------------------ */ /** EqualsExpr ::= `=' Expr From 3183c5078c86eae0e7e421ac15286a6becb90885 Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Fri, 27 Apr 2018 20:27:55 +0200 Subject: [PATCH 03/11] Fix #4373: reject wildcard types in syntactically invalid positions Fix #4373. The testcase is from examples in #4373, variations and tests for types with wildcards. --- .../dotty/tools/dotc/parsing/Parsers.scala | 14 +++++------ tests/neg/i4373.scala | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 tests/neg/i4373.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 6c38aa2bba22..4d6e7835f2c1 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -468,9 +468,9 @@ object Parsers { val l = opInfo.operand val r = top if (isType && !op.isBackquoted && op.name == tpnme.raw.BAR) { - OrTypeTree(l, r) + OrTypeTree(checkWildcard(l), checkWildcard(r)) } else if (isType && !op.isBackquoted && op.name == tpnme.raw.AMP) { - AndTypeTree(l, r) + AndTypeTree(checkWildcard(l), checkWildcard(r)) } else InfixOp(l, op, r) } @@ -784,7 +784,7 @@ object Parsers { val start = in.offset val tparams = typeParamClause(ParamOwner.TypeParam) if (in.token == ARROW) - atPos(start, in.skipToken())(LambdaTypeTree(tparams, typ())) + atPos(start, in.skipToken())(LambdaTypeTree(tparams, toplevelTyp())) else { accept(ARROW); typ() } } else infixType() @@ -822,7 +822,7 @@ object Parsers { def refinedTypeRest(t: Tree): Tree = { newLineOptWhenFollowedBy(LBRACE) - if (in.token == LBRACE) refinedTypeRest(atPos(startOffset(t)) { RefinedTypeTree(t, refinement()) }) + if (in.token == LBRACE) refinedTypeRest(atPos(startOffset(t)) { RefinedTypeTree(checkWildcard(t), refinement()) }) else t } @@ -886,7 +886,7 @@ object Parsers { private def simpleTypeRest(t: Tree): Tree = in.token match { case HASH => simpleTypeRest(typeProjection(t)) case LBRACKET => simpleTypeRest(atPos(startOffset(t)) { - AppliedTypeTree(t, typeArgs(namedOK = false, wildOK = true)) }) + AppliedTypeTree(checkWildcard(t), typeArgs(namedOK = false, wildOK = true)) }) case _ => t } @@ -2159,7 +2159,7 @@ object Parsers { in.token match { case EQUALS => in.nextToken() - TypeDef(name, lambdaAbstract(tparams, typ())).withMods(mods).setComment(in.getDocComment(start)) + TypeDef(name, lambdaAbstract(tparams, toplevelTyp())).withMods(mods).setComment(in.getDocComment(start)) case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | EOF => TypeDef(name, lambdaAbstract(tparams, typeBounds())).withMods(mods).setComment(in.getDocComment(start)) case _ => @@ -2287,7 +2287,7 @@ object Parsers { /** ConstrApp ::= SimpleType {ParArgumentExprs} */ val constrApp = () => { - val t = annotType() + val t = checkWildcard(annotType()) if (in.token == LPAREN) parArgumentExprss(wrapNew(t)) else t } diff --git a/tests/neg/i4373.scala b/tests/neg/i4373.scala new file mode 100644 index 000000000000..349985521856 --- /dev/null +++ b/tests/neg/i4373.scala @@ -0,0 +1,23 @@ +trait Base +trait TypeConstr[X] + +class X1[A >: _ | X1[_]] // error +class X2[A >: _ & X2[_]] // error +class X3[A >: X3[_] | _] // error +class X4[A >: X4[_] & _] // error + +class A1 extends _ // error +class A2 extends _ with _ // error // error +class A3 extends Base with _ // error +class A4 extends _ with Base // error + +object Test { + type T1 = _ // error + type T2 = _[Int] // error + type T3 = _ { type S } // error + type T4 = [X] => _ // error + + // Open questions: + type T5 = TypeConstr[_ { type S }] // error + type T5 = TypeConstr[_[Int]] // error +} From 02a8f1472a3ae2ec6b99f6a9e4a7e4d467f4d610 Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Mon, 30 Apr 2018 19:43:47 +0200 Subject: [PATCH 04/11] Avoid cascade type errors from error-correction-generated code Without this commit, the testcase produces additional spurious errors: ```scala -- [E104] Syntax Error: tests/neg/i4373.scala:10:0 ----------------------------- 10 |class A2 extends _ with _ // error // error |^ |class Any is not a trait longer explanation available when compiling with `-explain` -- [E104] Syntax Error: tests/neg/i4373.scala:11:21 ---------------------------- 11 |class A3 extends Base with _ // error | ^ | class Any is not a trait longer explanation available when compiling with `-explain` -- Error: tests/neg/i4373.scala:12:24 ------------------------------------------ 12 |class A4 extends _ with Base // error | ^^^^ |illegal trait inheritance: superclass Any does not derive from trait Base's superclass Object ``` These errors make absolutely no sense for a user, since they refer to code the user didn't write, but that was generated by the compiler's error correction mechanism. I haven't checked if we could use `Ident(nme.ERROR)` everywhere. I have also tried using `EmptyTree` and `EmptyTree.withPos(wildcardPos)` and `EmptyTree.clone.withPos(wildcardPos)` as fallback trees, but all of them failed in some way. --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 4d6e7835f2c1..09a9fcce363c 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2287,7 +2287,8 @@ object Parsers { /** ConstrApp ::= SimpleType {ParArgumentExprs} */ val constrApp = () => { - val t = checkWildcard(annotType()) + // Using Ident(nme.ERROR) to avoid causing cascade errors on non-user-written code + val t = checkWildcard(annotType(), fallbackTree = Ident(nme.ERROR)) if (in.token == LPAREN) parArgumentExprss(wrapNew(t)) else t } From f4ea23c185991cb165101ab4907b213b95cf34be Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Tue, 1 May 2018 15:25:04 +0200 Subject: [PATCH 05/11] Add and fix missing testcases with `with` --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 2 +- tests/neg/i4373.scala | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 09a9fcce363c..bc262b30efd6 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -835,7 +835,7 @@ object Parsers { if (ctx.settings.strict.value) deprecationWarning(DeprecatedWithOperator()) in.nextToken() - AndTypeTree(t, withType()) + AndTypeTree(checkWildcard(t), checkWildcard(withType())) } else t diff --git a/tests/neg/i4373.scala b/tests/neg/i4373.scala index 349985521856..95ac282e743e 100644 --- a/tests/neg/i4373.scala +++ b/tests/neg/i4373.scala @@ -5,6 +5,8 @@ class X1[A >: _ | X1[_]] // error class X2[A >: _ & X2[_]] // error class X3[A >: X3[_] | _] // error class X4[A >: X4[_] & _] // error +class X5[A >: _ with X5[_]] // error +class X6[A >: X6[_] with _] // error class A1 extends _ // error class A2 extends _ with _ // error // error From 95d090172e4f12953b227b4386a3c10f815065e2 Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Wed, 2 May 2018 22:31:06 +0200 Subject: [PATCH 06/11] Handle by-name types better --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 13 ++++++++++--- .../tools/dotc/reporting/diagnostic/messages.scala | 4 ++-- tests/neg/i4373.scala | 10 +++++++++- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index bc262b30efd6..d6b0d26812d9 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -768,9 +768,16 @@ object Parsers { accept(RPAREN) if (imods.is(Implicit) || isValParamList || in.token == ARROW) functionRest(ts) else { - for (t <- ts) - if (t.isInstanceOf[ByNameTypeTree]) - syntaxError(ByNameParameterNotSupported()) + val ts1 = + for (t <- ts) yield { + t match { + case t@ByNameTypeTree(t1) => + syntaxError(ByNameParameterNotSupported(t), t.pos) + t1 + case _ => + t + } + } val tuple = atPos(start) { makeTupleOrParens(ts) } infixTypeRest( refinedTypeRest( diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 3abc06caddf7..ef685b0dc0f2 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -696,10 +696,10 @@ object messages { } } - case class ByNameParameterNotSupported()(implicit ctx: Context) + case class ByNameParameterNotSupported(tpe: untpd.TypTree)(implicit ctx: Context) extends Message(ByNameParameterNotSupportedID) { val kind = "Syntax" - val msg = "By-name parameter type not allowed here." + val msg = hl"By-name parameter type ${tpe} not allowed here." val explanation = hl"""|By-name parameters act like functions that are only evaluated when referenced, diff --git a/tests/neg/i4373.scala b/tests/neg/i4373.scala index 95ac282e743e..76b80e12fa7f 100644 --- a/tests/neg/i4373.scala +++ b/tests/neg/i4373.scala @@ -21,5 +21,13 @@ object Test { // Open questions: type T5 = TypeConstr[_ { type S }] // error - type T5 = TypeConstr[_[Int]] // error + type T6 = TypeConstr[_[Int]] // error + + // expression types + type T7 = (=> Int) | (Int => Int) // error + type T8 = (=> Int) & (Int => Int) // error + type T9 = (=> Int) with (Int => Int) // error + type T10 = (Int => Int) | (=> Int) // error + type T11 = (Int => Int) & (=> Int) // error + type T12 = (Int => Int) with (=> Int) // error } From c17ed3eade7b52ee36219cdc0d098f95c1dc79bf Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Wed, 2 May 2018 23:03:39 +0200 Subject: [PATCH 07/11] Refactor, simplify and extend wildcard checking This is mostly a refactoring, though `findWildcardType(t, alsoNonValue = true)` is new behavior that belongs later. `rejectWildcard` had leftover tortous abstration, which is removed here. --- .../dotty/tools/dotc/parsing/Parsers.scala | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index d6b0d26812d9..5761c1a9ca11 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1012,23 +1012,28 @@ object Parsers { * If it is, returns the [[Position]] where the wildcard occurs. */ @tailrec - private final def findWildcardType(t: Tree): Option[Position] = t match { - case TypeBoundsTree(_, _) => Some(t.pos) - case Parens(t1) => findWildcardType(t1) - case Annotated(t1, _) => findWildcardType(t1) + private final def findWildcardType(t: Tree, alsoNonValue: Boolean): Option[Tree] = t match { + case TypeBoundsTree(_, _) => Some(t) + case ByNameTypeTree(_) if alsoNonValue => Some(t) + case Parens(t1) => findWildcardType(t1, alsoNonValue) + case Annotated(t1, _) => findWildcardType(t1, alsoNonValue) case _ => None } - def rejectWildcard(t: Tree, report: Position => Unit, fallbackTree: Tree): Tree = - findWildcardType(t) match { - case Some(wildcardPos) => - report(wildcardPos) + def rejectWildcard(t: Tree, fallbackTree: Tree): Tree = + findWildcardType(t, false) match { + case Some(wildcardTree) => + syntaxError(UnboundWildcardType(), wildcardTree.pos) fallbackTree case None => t } + def checkWildcard(t: Tree, wildOK: Boolean = false, fallbackTree: Tree = scalaAny): Tree = - if (wildOK) t else rejectWildcard(t, syntaxError(UnboundWildcardType(), _), fallbackTree) + if (wildOK) + t + else + rejectWildcard(t, fallbackTree) /* ----------- EXPRESSIONS ------------------------------------------------ */ From 3ddd88a83949eb970ffe6ebec9ea07b16e66d3b3 Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Wed, 2 May 2018 23:06:32 +0200 Subject: [PATCH 08/11] Reject by-name types as arguments of AndTypeTree and OrTypeTree Those types lead to assertion failures later while building OrTypeTree. Reject them, also for AndTypeTree. --- .../dotty/tools/dotc/parsing/Parsers.scala | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 5761c1a9ca11..fa4cfcae5efd 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -468,9 +468,9 @@ object Parsers { val l = opInfo.operand val r = top if (isType && !op.isBackquoted && op.name == tpnme.raw.BAR) { - OrTypeTree(checkWildcard(l), checkWildcard(r)) + OrTypeTree(checkAndOrArgument(l), checkAndOrArgument(r)) } else if (isType && !op.isBackquoted && op.name == tpnme.raw.AMP) { - AndTypeTree(checkWildcard(l), checkWildcard(r)) + AndTypeTree(checkAndOrArgument(l), checkAndOrArgument(r)) } else InfixOp(l, op, r) } @@ -842,7 +842,7 @@ object Parsers { if (ctx.settings.strict.value) deprecationWarning(DeprecatedWithOperator()) in.nextToken() - AndTypeTree(checkWildcard(t), checkWildcard(withType())) + AndTypeTree(checkAndOrArgument(t), checkAndOrArgument(withType())) } else t @@ -1035,6 +1035,19 @@ object Parsers { else rejectWildcard(t, fallbackTree) + def checkAndOrArgument(t: Tree): Tree = + findWildcardType(t, true) match { + case Some(typTree) => + typTree match { + case typTree: TypeBoundsTree => + syntaxError(UnboundWildcardType(), typTree.pos) + case typTree: ByNameTypeTree => + syntaxError(ByNameParameterNotSupported(typTree), typTree.pos) + } + scalaAny + case None => t + } + /* ----------- EXPRESSIONS ------------------------------------------------ */ /** EqualsExpr ::= `=' Expr From 7f3a0cf6d0a4f313c71260da72c14b3fbc438caf Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Thu, 3 May 2018 16:06:26 +0200 Subject: [PATCH 09/11] Add some testcases --- tests/neg/i4373a.scala | 3 +++ tests/neg/i4373b.scala | 4 ++++ tests/neg/i4373c.scala | 3 +++ 3 files changed, 10 insertions(+) create mode 100644 tests/neg/i4373a.scala create mode 100644 tests/neg/i4373b.scala create mode 100644 tests/neg/i4373c.scala diff --git a/tests/neg/i4373a.scala b/tests/neg/i4373a.scala new file mode 100644 index 000000000000..d0e9505b8c44 --- /dev/null +++ b/tests/neg/i4373a.scala @@ -0,0 +1,3 @@ +// ==> 040fb47fbaf718cecb11a7d51ac5a48bf4f6a1fe.scala <== +object x0 { + val x0 : _ with // error // error // error diff --git a/tests/neg/i4373b.scala b/tests/neg/i4373b.scala new file mode 100644 index 000000000000..dee55114da66 --- /dev/null +++ b/tests/neg/i4373b.scala @@ -0,0 +1,4 @@ +// ==> 05bef7805687ba94da37177f7568e3ba7da1f91c.scala <== +class x0 { + x1: // error + x0 | _ // error // error diff --git a/tests/neg/i4373c.scala b/tests/neg/i4373c.scala new file mode 100644 index 000000000000..8f0246b6cdee --- /dev/null +++ b/tests/neg/i4373c.scala @@ -0,0 +1,3 @@ +// ==> 18b253a4a89a84c5674165c6fc3efafad535eee3.scala <== +object x0 { + def x1[x2 <:_[ // error // error // error From 35f09c4c2b6ca7d789b61a4676da870160fce733 Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Thu, 3 May 2018 16:41:21 +0200 Subject: [PATCH 10/11] Review feedback: findWildcardType -> findNonValueTypeTree --- .../src/dotty/tools/dotc/parsing/Parsers.scala | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index fa4cfcae5efd..f3a1218f69aa 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1008,20 +1008,20 @@ object Parsers { else if (location == Location.InPattern) refinedType() else infixType() - /** Checks whether `t` is a wildcard type. - * If it is, returns the [[Position]] where the wildcard occurs. + /** 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 findWildcardType(t: Tree, alsoNonValue: Boolean): Option[Tree] = t match { + 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) => findWildcardType(t1, alsoNonValue) - case Annotated(t1, _) => findWildcardType(t1, alsoNonValue) + case Parens(t1) => findNonValueTypeTree(t1, alsoNonValue) + case Annotated(t1, _) => findNonValueTypeTree(t1, alsoNonValue) case _ => None } def rejectWildcard(t: Tree, fallbackTree: Tree): Tree = - findWildcardType(t, false) match { + findNonValueTypeTree(t, false) match { case Some(wildcardTree) => syntaxError(UnboundWildcardType(), wildcardTree.pos) fallbackTree @@ -1036,7 +1036,7 @@ object Parsers { rejectWildcard(t, fallbackTree) def checkAndOrArgument(t: Tree): Tree = - findWildcardType(t, true) match { + findNonValueTypeTree(t, true) match { case Some(typTree) => typTree match { case typTree: TypeBoundsTree => From 0804fde3e58ea07f9d852e356f62f236a3e268a2 Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Thu, 3 May 2018 16:50:39 +0200 Subject: [PATCH 11/11] Exhaustive testing of permutations with annotations --- tests/neg/i4373.scala | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/neg/i4373.scala b/tests/neg/i4373.scala index 76b80e12fa7f..6ba7c81a617a 100644 --- a/tests/neg/i4373.scala +++ b/tests/neg/i4373.scala @@ -30,4 +30,22 @@ object Test { type T10 = (Int => Int) | (=> Int) // error type T11 = (Int => Int) & (=> Int) // error type T12 = (Int => Int) with (=> Int) // error + + // annotations + type T13 = _ @ annotation.tailrec // error + type T14 = Int @ _ // error + type T15 = (_ | Int) @ annotation.tailrec // error + type T16 = (Int | _) @ annotation.tailrec // error + type T17 = Int @ (_ | annotation.tailrec) // error + type T18 = Int @ (annotation.tailrec | _) // error + + 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 T23 = (_ & Int) @ annotation.tailrec // error + type T24 = (Int & _) @ annotation.tailrec // error + type T25 = Int @ (_ & annotation.tailrec) // error + type T26 = Int @ (annotation.tailrec & _) // error }