Skip to content

Commit 1cb67c4

Browse files
committed
Reject unbound wildcard types
1 parent 1a84845 commit 1cb67c4

File tree

1 file changed

+27
-9
lines changed

1 file changed

+27
-9
lines changed

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

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import StdNames._
1919
import util.Positions._
2020
import Constants._
2121
import ScriptParsers._
22-
import annotation.switch
22+
import scala.annotation.{tailrec, switch}
2323
import util.DotClass
2424
import rewrite.Rewrites.patch
2525

@@ -648,12 +648,19 @@ object Parsers {
648648
}
649649

650650
/* ------------- TYPES ------------------------------------------------------ */
651+
/** Same as [[typ]], but emits a syntax error if it returns a wildcard.
652+
*/
653+
def toplevelTyp(): Tree = {
654+
val t = typ()
655+
for (wildcardPos <- findWildcardType(t)) syntaxError("unbound wildcard type", wildcardPos)
656+
t
657+
}
651658

652-
/** Type ::= FunArgTypes `=>' Type
659+
/** Type ::= FunArgTypes `=>' Type
653660
* | HkTypeParamClause `->' Type
654-
* | InfixType
661+
* | InfixType
655662
* FunArgTypes ::= InfixType
656-
* | `(' [ FunArgType {`,' FunArgType } ] `)'
663+
* | `(' [ FunArgType {`,' FunArgType } ] `)'
657664
*/
658665
def typ(): Tree = {
659666
val start = in.offset
@@ -823,7 +830,7 @@ object Parsers {
823830
/** ParamValueType ::= Type [`*']
824831
*/
825832
def paramValueType(): Tree = {
826-
val t = typ()
833+
val t = toplevelTyp()
827834
if (isIdent(nme.raw.STAR)) {
828835
in.nextToken()
829836
atPos(t.pos.start) { PostfixOp(t, nme.raw.STAR) }
@@ -845,7 +852,7 @@ object Parsers {
845852
atPos(in.offset) { TypeBoundsTree(bound(SUPERTYPE), bound(SUBTYPE)) }
846853

847854
private def bound(tok: Int): Tree =
848-
if (in.token == tok) { in.nextToken(); typ() }
855+
if (in.token == tok) { in.nextToken(); toplevelTyp() }
849856
else EmptyTree
850857

851858
/** TypeParamBounds ::= TypeBounds {`<%' Type} {`:' Type}
@@ -859,26 +866,37 @@ object Parsers {
859866
def contextBounds(pname: TypeName): List[Tree] = in.token match {
860867
case COLON =>
861868
atPos(in.skipToken) {
862-
AppliedTypeTree(typ(), Ident(pname))
869+
AppliedTypeTree(toplevelTyp(), Ident(pname))
863870
} :: contextBounds(pname)
864871
case VIEWBOUND =>
865872
deprecationWarning("view bounds `<%' are deprecated, use a context bound `:' instead")
866873
atPos(in.skipToken) {
867-
Function(Ident(pname) :: Nil, typ())
874+
Function(Ident(pname) :: Nil, toplevelTyp())
868875
} :: contextBounds(pname)
869876
case _ =>
870877
Nil
871878
}
872879

873880
def typedOpt(): Tree =
874-
if (in.token == COLON) { in.nextToken(); typ() }
881+
if (in.token == COLON) { in.nextToken(); toplevelTyp() }
875882
else TypeTree()
876883

877884
def typeDependingOn(location: Location.Value): Tree =
878885
if (location == Location.InParens) typ()
879886
else if (location == Location.InPattern) refinedType()
880887
else infixType()
881888

889+
/** Checks whether `t` is a wildcard type.
890+
* If it is, returns the [[Position]] where the wildcard occurs.
891+
*/
892+
@tailrec
893+
private final def findWildcardType(t: Tree): Option[Position] = t match {
894+
case TypeBoundsTree(_, _) => Some(t.pos)
895+
case Parens(t1) => findWildcardType(t1)
896+
case Annotated(_, t1) => findWildcardType(t1)
897+
case _ => None
898+
}
899+
882900
/* ----------- EXPRESSIONS ------------------------------------------------ */
883901

884902
/** EqualsExpr ::= `=' Expr

0 commit comments

Comments
 (0)