Skip to content

Commit c966be0

Browse files
authored
Merge pull request #4401 from dotty-staging/fix-fuzzing-1
Fixes for fuzzing tests reported on Gitter
2 parents b4bfbcb + d03e26c commit c966be0

28 files changed

+136
-49
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -527,17 +527,18 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
527527
case _ =>
528528
}
529529
either(recur(tp1, tp21), recur(tp1, tp22)) || fourthTry
530-
case tp2: MethodOrPoly =>
530+
case tp2: MethodType =>
531531
def compareMethod = tp1 match {
532-
case tp1: MethodOrPoly =>
533-
(tp1.signature consistentParams tp2.signature) &&
534-
matchingParams(tp1, tp2) &&
535-
(!tp2.isImplicitMethod || tp1.isImplicitMethod) &&
536-
isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1))
537-
case _ =>
538-
false
532+
case tp1: MethodType => compareMethodOrPoly(tp1, tp2)
533+
case _ => false
539534
}
540535
compareMethod
536+
case tp2: PolyType =>
537+
def comparePoly = tp1 match {
538+
case tp1: PolyType => compareMethodOrPoly(tp1, tp2)
539+
case _ => false
540+
}
541+
comparePoly
541542
case tp2 @ ExprType(restpe2) =>
542543
def compareExpr = tp1 match {
543544
// We allow ()T to be a subtype of => T.
@@ -573,6 +574,12 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
573574
fourthTry
574575
}
575576

577+
def compareMethodOrPoly(tp1: MethodOrPoly, tp2: MethodOrPoly) =
578+
(tp1.signature consistentParams tp2.signature) &&
579+
matchingParams(tp1, tp2) &&
580+
(!tp2.isImplicitMethod || tp1.isImplicitMethod) &&
581+
isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1))
582+
576583
def fourthTry: Boolean = tp1 match {
577584
case tp1: TypeRef =>
578585
tp1.info match {

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1804,10 +1804,11 @@ object Types {
18041804
param.derivedSingleDenotation(param, argInfo)
18051805
}
18061806
else {
1807-
assert(ctx.reporter.errorsReported,
1808-
i"""bad parameter reference $this at ${ctx.phase}
1809-
|the parameter is ${param.showLocated} but the prefix $prefix
1810-
|does not define any corresponding arguments.""")
1807+
if (!ctx.reporter.errorsReported)
1808+
throw new TypeError(
1809+
i"""bad parameter reference $this at ${ctx.phase}
1810+
|the parameter is ${param.showLocated} but the prefix $prefix
1811+
|does not define any corresponding arguments.""")
18111812
NoDenotation
18121813
}
18131814
}

compiler/src/dotty/tools/dotc/core/Uniques.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ object Uniques {
6262
if (h == NotCached) newType
6363
else {
6464
val r = findPrevious(h, prefix, designator)
65-
if (r ne null) r else addEntryAfterScan(newType)
65+
if ((r ne null) && (r.isTerm == isTerm)) r else addEntryAfterScan(newType)
6666
}
6767
}
6868
}

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

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,7 +1929,10 @@ object Parsers {
19291929
commaSeparated(importExpr) match {
19301930
case t :: rest =>
19311931
// The first import should start at the position of the keyword.
1932-
t.withPos(t.pos.withStart(offset)) :: rest
1932+
val firstPos =
1933+
if (t.pos.exists) t.pos.withStart(offset)
1934+
else Position(offset, in.lastOffset)
1935+
t.withPos(firstPos) :: rest
19331936
case nil => nil
19341937
}
19351938
}
@@ -2422,22 +2425,35 @@ object Parsers {
24222425
(self, if (stats.isEmpty) List(EmptyTree) else stats.toList)
24232426
}
24242427

2425-
/** RefineStatSeq ::= RefineStat {semi RefineStat}
2426-
* RefineStat ::= Dcl
2427-
* |
2428-
* (in reality we admit Defs and filter them out afterwards)
2428+
/** RefineStatSeq ::= RefineStat {semi RefineStat}
2429+
* RefineStat ::= ‘val’ VarDcl
2430+
* | ‘def’ DefDcl
2431+
* | ‘type’ {nl} TypeDcl
2432+
* (in reality we admit Defs and vars and filter them out afterwards in `checkLegal`)
24292433
*/
24302434
def refineStatSeq(): List[Tree] = {
24312435
val stats = new ListBuffer[Tree]
2436+
def checkLegal(tree: Tree): List[Tree] = {
2437+
val isLegal = tree match {
2438+
case tree: ValDef => tree.rhs.isEmpty && !tree.mods.flags.is(Mutable)
2439+
case tree: DefDef => tree.rhs.isEmpty
2440+
case tree: TypeDef => true
2441+
case _ => false
2442+
}
2443+
if (isLegal) tree :: Nil
2444+
else {
2445+
syntaxError("illegal refinement", tree.pos)
2446+
Nil
2447+
}
2448+
}
24322449
while (!isStatSeqEnd) {
2433-
if (isDclIntro) {
2434-
stats += defOrDcl(in.offset, Modifiers())
2435-
} else if (!isStatSep) {
2450+
if (isDclIntro)
2451+
stats ++= checkLegal(defOrDcl(in.offset, Modifiers()))
2452+
else if (!isStatSep)
24362453
syntaxErrorOrIncomplete(
24372454
"illegal start of declaration" +
24382455
(if (inFunReturnType) " (possible cause: missing `=' in front of current method body)"
24392456
else ""))
2440-
}
24412457
acceptStatSepUnlessAtEnd()
24422458
}
24432459
stats.toList

compiler/src/dotty/tools/dotc/printing/Formatting.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ object Formatting {
167167
entry match {
168168
case param: TypeParamRef =>
169169
s"is a type variable${addendum("constraint", ctx.typeComparer.bounds(param))}"
170+
case param: TermParamRef =>
171+
s"is a reference to a value parameter"
170172
case sym: Symbol =>
171173
val info =
172174
if (ctx.gadt.bounds.contains(sym))

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
366366
val denot = cx.denotNamed(getterName)
367367
if (denot.exists) ref(TermRef(cx.owner.thisType, getterName, denot))
368368
else {
369-
assert(ctx.mode.is(Mode.Interactive),
369+
assert(ctx.mode.is(Mode.Interactive) || ctx.reporter.errorsReported,
370370
s"non-existent getter denotation ($denot) for getter($getterName)")
371371
findGetter(cx.outer)
372372
}
@@ -720,7 +720,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
720720
}
721721

722722
fun1.tpe match {
723-
case err: ErrorType => untpd.cpy.Apply(tree)(fun1, tree.args).withType(err)
723+
case err: ErrorType => untpd.cpy.Apply(tree)(fun1, proto.typedArgs).withType(err)
724724
case TryDynamicCallType => typedDynamicApply(tree, pt)
725725
case _ =>
726726
if (originalProto.isDropped) fun1
@@ -967,6 +967,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
967967
case Apply(Apply(unapply, `dummyArg` :: Nil), args2) => assert(args2.nonEmpty); args2
968968
case Apply(unapply, `dummyArg` :: Nil) => Nil
969969
case Inlined(u, _, _) => unapplyImplicits(u)
970+
case _ => assert(ctx.reporter.errorsReported); Nil
970971
}
971972

972973
var argTypes = unapplyArgs(unapplyApp.tpe, unapplyFn, args, tree.pos)

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import config.Printers.typr
3232
import NameKinds.DefaultGetterName
3333

3434
import collection.mutable
35-
import SymDenotations.NoCompleter
35+
import SymDenotations.{NoCompleter, NoDenotation}
3636
import dotty.tools.dotc.reporting.diagnostic.{ErrorMessageID, Message}
3737
import dotty.tools.dotc.reporting.diagnostic.messages._
3838
import dotty.tools.dotc.transform.ValueClasses._
@@ -774,20 +774,25 @@ trait Checking {
774774
case Nil =>
775775
}
776776

777-
/** Check that all named type that form part of this type have a denotation.
777+
/** Check that all named types that form part of this type have a denotation.
778778
* Called on inferred (result) types of ValDefs and DefDefs.
779779
* This could fail for types where the member was originally available as part
780780
* of the self type, yet is no longer visible once the `this` has been replaced
781781
* by some other prefix. See neg/i3083.scala
782782
*/
783783
def checkMembersOK(tp: Type, pos: Position)(implicit ctx: Context): Type = {
784+
var ok = true
784785
val check: Type => Unit = {
785-
case ref: NamedType if !ref.denot.exists =>
786-
ctx.error(em"$ref is not defined in inferred type $tp", pos)
786+
case ref: NamedType =>
787+
val d = try ref.denot catch { case ex: TypeError => NoDenotation }
788+
if (!d.exists) {
789+
ctx.error(em"$ref is not defined in inferred type $tp", pos)
790+
ok = false
791+
}
787792
case _ =>
788793
}
789794
tp.foreachPart(check, stopAtStatic = true)
790-
tp
795+
if (ok) tp else UnspecifiedErrorType
791796
}
792797

793798
/** Check that all non-synthetic references of the form `<ident>` or

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -907,14 +907,19 @@ class Namer { typer: Typer =>
907907
case TypeApply(core, targs) => (core, targs)
908908
case core => (core, Nil)
909909
}
910-
val Select(New(tpt), nme.CONSTRUCTOR) = core
911-
val targs1 = targs map (typedAheadType(_))
912-
val ptype = typedAheadType(tpt).tpe appliedTo targs1.tpes
913-
if (ptype.typeParams.isEmpty) ptype
914-
else {
915-
if (denot.is(ModuleClass) && denot.sourceModule.is(Implicit))
916-
missingType(denot.symbol, "parent ")(creationContext)
917-
fullyDefinedType(typedAheadExpr(parent).tpe, "class parent", parent.pos)
910+
core match {
911+
case Select(New(tpt), nme.CONSTRUCTOR) =>
912+
val targs1 = targs map (typedAheadType(_))
913+
val ptype = typedAheadType(tpt).tpe appliedTo targs1.tpes
914+
if (ptype.typeParams.isEmpty) ptype
915+
else {
916+
if (denot.is(ModuleClass) && denot.sourceModule.is(Implicit))
917+
missingType(denot.symbol, "parent ")(creationContext)
918+
fullyDefinedType(typedAheadExpr(parent).tpe, "class parent", parent.pos)
919+
}
920+
case _ =>
921+
assert(ctx.reporter.errorsReported)
922+
UnspecifiedErrorType
918923
}
919924
}
920925

compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ trait TypeAssigner {
256256
def accessibleSelectionType(tree: untpd.RefTree, qual1: Tree)(implicit ctx: Context): Type = {
257257
var qualType = qual1.tpe.widenIfUnstable
258258
if (qualType.isLambdaSub) qualType = errorType(em"$qualType takes type parameters", qual1.pos)
259+
else if (!qualType.isInstanceOf[TermType]) qualType = errorType(em"$qualType is illegal as a selection prefix", qual1.pos)
259260
val ownType = selectionType(qualType, tree.name, tree.pos)
260261
ensureAccessible(ownType, qual1.isInstanceOf[Super], tree.pos)
261262
}

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,7 +1186,7 @@ class Typer extends Namer
11861186
val refineCls = createSymbol(refineClsDef).asClass
11871187
val TypeDef(_, impl: Template) = typed(refineClsDef)
11881188
val refinements1 = impl.body
1189-
assert(tree.refinements.length == refinements1.length, s"${tree.refinements} != $refinements1")
1189+
assert(tree.refinements.hasSameLengthAs(refinements1), i"${tree.refinements}%, % > $refinements1%, %")
11901190
val seen = mutable.Set[Symbol]()
11911191
for (refinement <- refinements1) { // TODO: get clarity whether we want to enforce these conditions
11921192
typr.println(s"adding refinement $refinement")
@@ -2441,7 +2441,7 @@ class Typer extends Namer
24412441
if (isFullyDefined(wtp, force = ForceDegree.all) &&
24422442
ctx.typerState.constraint.ne(prevConstraint)) readapt(tree)
24432443
else err.typeMismatch(tree, pt, failure)
2444-
if (ctx.mode.is(Mode.ImplicitsEnabled))
2444+
if (ctx.mode.is(Mode.ImplicitsEnabled) && tree.typeOpt.isValueType)
24452445
inferView(tree, pt) match {
24462446
case SearchSuccess(inferred, _, _) =>
24472447
checkImplicitConversionUseOK(inferred.symbol, tree.pos)

docs/docs/internals/syntax.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ ParamValueType ::= Type [‘*’]
147147
TypeArgs ::= ‘[’ ArgTypes ‘]’ ts
148148
NamedTypeArg ::= id ‘=’ Type NamedArg(id, t)
149149
NamedTypeArgs ::= ‘[’ NamedTypeArg {‘,’ NamedTypeArg} ‘]’ nts
150-
Refinement ::= ‘{’ [Dcl] {semi [Dcl]} ‘}’ ds
150+
Refinement ::= ‘{’ [RefineDcl] {semi [RefineDcl]} ‘}’ ds
151151
TypeBounds ::= [‘>:’ Type] [‘<:’ Type] | INT TypeBoundsTree(lo, hi)
152152
TypeParamBounds ::= TypeBounds {‘<%’ Type} {‘:’ Type} ContextBounds(typeBounds, tps)
153153
```
@@ -299,12 +299,12 @@ ImportSelector ::= id [‘=>’ id | ‘=>’ ‘_’]
299299

300300
### Declarations and Definitions
301301
```ebnf
302-
Dcl ::= ‘val’ ValDcl
303-
| ‘var’ VarDcl
302+
RefineDcl ::= ‘val’ VarDcl
304303
| ‘def’ DefDcl
305304
| ‘type’ {nl} TypeDcl
306305
| INT
307-
306+
Dcl ::= RefineDcl
307+
| ‘var’ VarDcl
308308
ValDcl ::= ids ‘:’ Type PatDef(_, ids, tpe, EmptyTree)
309309
VarDcl ::= ids ‘:’ Type PatDef(_, ids, tpe, EmptyTree)
310310
DefDcl ::= DefSig [‘:’ Type] DefDef(_, name, tparams, vparamss, tpe, EmptyTree)

tests/neg/i1640.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
object Test extends App {
22
List(1, 2, 3) map (_ match { case x => x + 1 })
3-
List((1, 2)) x (_ match { case (x, z) => x + z }) // error
3+
List((1, 2)) x (_ match { case (x, z) => x + z }) // error // error // error
44
}

tests/neg/i1641.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ package object println { def bippy(x: Int, y: Int, z: Int) = "(Int, Int, Int)" }
33
object Test {
44
def main(args: Array[String]): Unit = {
55
println(bar.bippy(5.5)) // error
6-
println(bar.bippy(1, 2, 3)) // error
6+
println(bar.bippy(1, 2, 3)) // error // error
77
}
88
}

tests/neg/i1707.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ object DepBug {
1818
}
1919
{ // error: Null does not take parameters (follow on)
2020
import dep._
21-
a m (b)
21+
a m (b) // error: not found: a
2222
}
2323
dep.a m (dep b) // error (follow on)
2424
}

tests/neg/illegal-refinements.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
trait x0 {
2+
3+
type T = String { val x: Int = 1 } // error: illegal refinement
4+
type U = String { def x(): Int = 1 } // error: illegal refinement
5+
type V = String { var x: Int } // error: illegal refinement
6+
7+
}

tests/neg/parser-stability-1.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object x0 {
2+
x1 match // error
3+
def this // error // error

tests/neg/parser-stability-10.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
object i0 {
2+
def unapply(i1: Int)(i6: List[Int]): Int = {
3+
def i7(i8: i0) = i1 match { // error
4+
case i0(_) => // error
5+
(i1, i8) match {
6+
case i0(i1, i1) => case _ => i2 // error // error
7+
}
8+
}
9+
} // error
10+
object i5 {
11+
import collection.mutable._
12+
try { ??? mutable { case i1(i5, i3, i4) => i5 }} // error // error // error
13+
} // error

tests/neg/parser-stability-2.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
trait x0 {
2+
new _ // error // error

tests/neg/parser-stability-3.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
object x0 {
2+
def x0(x1: x2 = 0, x1 x3) x4 = // error // error // error
3+
x5 x6 x7[x8[x9 x2]] = x0
4+
val x10 = x0( ) // error // error

tests/neg/parser-stability-4.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class x0{
2+
def x0: x0 = (x0 => x0) => x0) // error // error

tests/neg/parser-stability-5.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait x0 {
2+
x1 : { // error
3+
var x2 // error // error

tests/neg/parser-stability-6.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class x0 {
2+
1 + x1 * / |= 2 // error: not found: x1
3+
}

tests/neg/parser-stability-7.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class x0[x1] {
2+
def x2: x1
3+
}
4+
trait x3 extends x0 {
5+
class x2
6+
var x2 = 0 // error
7+
var x4 = x5 x2 // error
8+
}

tests/neg/parser-stability-8.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
case class I0 extends this // error // error

tests/neg/parser-stability-9.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import // error

tests/neg/parser-stability.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class I2[I2] {
2+
def I2: I2 = (I2 => I2) => I2 // error // error

tests/neg/structural.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ object Test3 {
33
def g(x: { type T ; def t: T ; def f(a: T): Boolean }) = x.f(x.t) // error: no ClassTag for x.T
44
g(new { type T = Int; def t = 4; def f(a:T) = true })
55
g(new { type T = Any; def t = 4; def f(a:T) = true })
6-
val y: { type T = Int; def t = 4; def f(a:T) = true }
6+
val y: { type T = Int; def t = 4; def f(a:T) = true } // error: illegal refinement // error: illegal refinement
77
= new { type T = Int; def t = 4; def f(a:T) = true }
88

99
def h(x: { def f[T](a: T): Int }) = x.f[Int](4) // error: polymorphic refinement method ... no longer allowed

tests/neg/t7239.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ object Test {
1717
(implicit F0: NoImplicit): HasWithFilter = ???
1818
}
1919

20-
BrokenMethod().withFilter(_ => true) // error
20+
BrokenMethod().withFilter(_ => true) // error // error
2121
BrokenMethod().filter(_ => true) // ok
2222

2323
locally {
@@ -35,6 +35,6 @@ object Test {
3535
// `(B => Boolean)`. Only later during pickling does the
3636
// defensive check for erroneous types in the tree pick up
3737
// the problem.
38-
BrokenMethod().withFilter(x => true) // error
38+
BrokenMethod().withFilter(x => true) // error // error
3939
}
4040
}

0 commit comments

Comments
 (0)