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
}