Skip to content

Commit 966dbb4

Browse files
committed
Fix scala#4373: reject wildcard types in syntactically invalid positions
Fix scala#4373. The testcase is from examples in scala#4373, variations and tests for types with wildcards. I'm unsure for a couple cases.
1 parent 861ac12 commit 966dbb4

File tree

3 files changed

+33
-7
lines changed

3 files changed

+33
-7
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,9 @@ object desugar {
892892
.withMods(mods)
893893
.withPos(original.pos.withPoint(named.pos.start))
894894

895+
def checkWildcard(t: Tree)(implicit ctx: Context): Tree =
896+
parsing.Parsers.rejectWildcard(t, ctx.error(UnboundWildcardType(), _), scalaAny)
897+
895898
/** Main desugaring method */
896899
def apply(tree: Tree)(implicit ctx: Context): Tree = {
897900

@@ -1114,8 +1117,8 @@ object desugar {
11141117
Apply(Select(Apply(Ident(nme.StringContext), strs), id), elems)
11151118
case InfixOp(l, op, r) =>
11161119
if (ctx.mode is Mode.Type)
1117-
if (!op.isBackquoted && op.name == tpnme.raw.AMP) AndTypeTree(l, r) // l & r
1118-
else if (!op.isBackquoted && op.name == tpnme.raw.BAR) OrTypeTree(l, r) // l | r
1120+
if (!op.isBackquoted && op.name == tpnme.raw.AMP) AndTypeTree(checkWildcard(l), checkWildcard(r)) // l & r
1121+
else if (!op.isBackquoted && op.name == tpnme.raw.BAR) OrTypeTree(checkWildcard(l), checkWildcard(r)) // l | r
11191122
else AppliedTypeTree(op, l :: r :: Nil) // op[l, r]
11201123
else {
11211124
assert(ctx.mode is Mode.Pattern) // expressions are handled separately by `binop`

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,7 @@ object Parsers {
795795
val start = in.offset
796796
val tparams = typeParamClause(ParamOwner.TypeParam)
797797
if (in.token == ARROW)
798-
atPos(start, in.skipToken())(LambdaTypeTree(tparams, typ()))
798+
atPos(start, in.skipToken())(LambdaTypeTree(tparams, toplevelTyp()))
799799
else { accept(ARROW); typ() }
800800
}
801801
else infixType()
@@ -833,7 +833,7 @@ object Parsers {
833833

834834
def refinedTypeRest(t: Tree): Tree = {
835835
newLineOptWhenFollowedBy(LBRACE)
836-
if (in.token == LBRACE) refinedTypeRest(atPos(startOffset(t)) { RefinedTypeTree(t, refinement()) })
836+
if (in.token == LBRACE) refinedTypeRest(atPos(startOffset(t)) { RefinedTypeTree(checkWildcard(t), refinement()) })
837837
else t
838838
}
839839

@@ -897,7 +897,7 @@ object Parsers {
897897
private def simpleTypeRest(t: Tree): Tree = in.token match {
898898
case HASH => simpleTypeRest(typeProjection(t))
899899
case LBRACKET => simpleTypeRest(atPos(startOffset(t)) {
900-
AppliedTypeTree(t, typeArgs(namedOK = false, wildOK = true)) })
900+
AppliedTypeTree(checkWildcard(t), typeArgs(namedOK = false, wildOK = true)) })
901901
case _ => t
902902
}
903903

@@ -2151,7 +2151,7 @@ object Parsers {
21512151
in.token match {
21522152
case EQUALS =>
21532153
in.nextToken()
2154-
TypeDef(name, lambdaAbstract(tparams, typ())).withMods(mods).setComment(in.getDocComment(start))
2154+
TypeDef(name, lambdaAbstract(tparams, toplevelTyp())).withMods(mods).setComment(in.getDocComment(start))
21552155
case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | EOF =>
21562156
TypeDef(name, lambdaAbstract(tparams, typeBounds())).withMods(mods).setComment(in.getDocComment(start))
21572157
case _ =>
@@ -2279,7 +2279,7 @@ object Parsers {
22792279
/** ConstrApp ::= SimpleType {ParArgumentExprs}
22802280
*/
22812281
val constrApp = () => {
2282-
val t = annotType()
2282+
val t = checkWildcard(annotType())
22832283
if (in.token == LPAREN) parArgumentExprss(wrapNew(t))
22842284
else t
22852285
}

tests/neg/i4373.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
trait Base
2+
trait TypeConstr[X]
3+
4+
class X1[A >: _ | X1[_]] // error
5+
class X2[A >: _ & X2[_]] // error
6+
class X3[A >: X3[_] | _] // error
7+
class X4[A >: X4[_] & _] // error
8+
9+
class A1 extends _ // error
10+
class A2 extends _ with _ // error // error
11+
class A3 extends Base with _ // error
12+
class A4 extends _ with Base // error
13+
14+
object Test {
15+
type T1 = _ // error
16+
type T2 = _[Int] // error
17+
type T3 = _ { type S } // error
18+
type T4 = [X] => _ // error
19+
20+
// Open questions:
21+
type T5 = TypeConstr[_ { type S }] // error
22+
type T5 = TypeConstr[_[Int]] // error
23+
}

0 commit comments

Comments
 (0)