Skip to content

Commit 75b66c8

Browse files
authored
Merge pull request #4411 from dotty-staging/fix-fuzzing-2
Fix more problems detected by fuzzing in #4389
2 parents 17c4497 + 690321d commit 75b66c8

28 files changed

+181
-78
lines changed

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,8 @@ object desugar {
8888
else {
8989
def msg =
9090
s"no matching symbol for ${tp.symbol.showLocated} in ${defctx.owner} / ${defctx.effectiveScope.toList}"
91-
if (ctx.reporter.errorsReported) ErrorType(msg)
92-
else throw new java.lang.Error(msg)
93-
}
91+
ErrorType(msg).assertingErrorsReported(msg)
92+
}
9493
case _ =>
9594
mapOver(tp)
9695
}

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

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -769,28 +769,26 @@ object Trees {
769769
def genericEmptyTree[T >: Untyped]: Thicket[T] = theEmptyTree.asInstanceOf[Thicket[T]]
770770

771771
def flatten[T >: Untyped](trees: List[Tree[T]]): List[Tree[T]] = {
772-
var buf: ListBuffer[Tree[T]] = null
773-
var xs = trees
774-
while (!xs.isEmpty) {
775-
xs.head match {
776-
case Thicket(elems) =>
777-
if (buf == null) {
778-
buf = new ListBuffer
779-
var ys = trees
780-
while (ys ne xs) {
781-
buf += ys.head
782-
ys = ys.tail
772+
def recur(buf: ListBuffer[Tree[T]], remaining: List[Tree[T]]): ListBuffer[Tree[T]] =
773+
remaining match {
774+
case Thicket(elems) :: remaining1 =>
775+
var buf1 = buf
776+
if (buf1 == null) {
777+
buf1 = new ListBuffer[Tree[T]]
778+
var scanned = trees
779+
while (scanned `ne` remaining) {
780+
buf1 += scanned.head
781+
scanned = scanned.tail
783782
}
784783
}
785-
for (elem <- elems) {
786-
assert(!elem.isInstanceOf[Thicket[_]])
787-
buf += elem
788-
}
789-
case tree =>
784+
recur(recur(buf1, elems), remaining1)
785+
case tree :: remaining1 =>
790786
if (buf != null) buf += tree
787+
recur(buf, remaining1)
788+
case nil =>
789+
buf
791790
}
792-
xs = xs.tail
793-
}
791+
val buf = recur(null, trees)
794792
if (buf != null) buf.toList else trees
795793
}
796794

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ object Constants {
153153
*/
154154
def convertTo(pt: Type)(implicit ctx: Context): Constant = {
155155
def classBound(pt: Type): Type = pt.dealias.stripTypeVar match {
156-
case tref: TypeRef if !tref.symbol.isClass => classBound(tref.info.bounds.lo)
156+
case tref: TypeRef if !tref.symbol.isClass && tref.info.exists =>
157+
classBound(tref.info.bounds.lo)
157158
case param: TypeParamRef =>
158159
ctx.typerState.constraint.entry(param) match {
159160
case TypeBounds(lo, hi) =>

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,16 @@ object Decorators {
175175
recur(enclosingInlineds, pos)
176176
}
177177

178-
implicit class reportingDeco[T](val x: T) extends AnyVal {
178+
implicit class genericDeco[T](val x: T) extends AnyVal {
179179
def reporting(op: T => String): T = { println(op(x)); x }
180+
def assertingErrorsReported(implicit ctx: Context): T = {
181+
assert(ctx.reporter.errorsReported)
182+
x
183+
}
184+
def assertingErrorsReported(msg: => String)(implicit ctx: Context): T = {
185+
assert(ctx.reporter.errorsReported, msg)
186+
x
187+
}
180188
}
181189

182190
implicit class StringInterpolators(val sc: StringContext) extends AnyVal {

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,10 +1466,11 @@ object SymDenotations {
14661466
if (classParents.isEmpty && !emptyParentsExpected)
14671467
onBehalf.signalProvisional()
14681468
val builder = new BaseDataBuilder
1469-
for (p <- classParents) {
1470-
if (p.typeSymbol.isClass) builder.addAll(p.typeSymbol.asClass.baseClasses)
1471-
else assert(isRefinementClass || ctx.mode.is(Mode.Interactive), s"$this has non-class parent: $p")
1472-
}
1469+
for (p <- classParents)
1470+
p.classSymbol match {
1471+
case pcls: ClassSymbol => builder.addAll(pcls.baseClasses)
1472+
case _ => assert(isRefinementClass || ctx.mode.is(Mode.Interactive), s"$this has non-class parent: $p")
1473+
}
14731474
(classSymbol :: builder.baseClasses, builder.baseClassSet)
14741475
}
14751476

@@ -1598,7 +1599,7 @@ object SymDenotations {
15981599
def collect(denots: PreDenotation, parents: List[Type]): PreDenotation = parents match {
15991600
case p :: ps =>
16001601
val denots1 = collect(denots, ps)
1601-
p.typeSymbol.denot match {
1602+
p.classSymbol.denot match {
16021603
case parentd: ClassDenotation =>
16031604
denots1 union
16041605
parentd.nonPrivateMembersNamed(name)
@@ -1747,7 +1748,7 @@ object SymDenotations {
17471748
var names = Set[Name]()
17481749
def maybeAdd(name: Name) = if (keepOnly(thisType, name)) names += name
17491750
for (p <- classParents)
1750-
for (name <- p.typeSymbol.asClass.memberNames(keepOnly))
1751+
for (name <- p.classSymbol.asClass.memberNames(keepOnly))
17511752
maybeAdd(name)
17521753
val ownSyms =
17531754
if (keepOnly eq implicitFilter)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
140140
val accu1 = if (accu exists (_ derivesFrom c)) accu else c :: accu
141141
if (cs == c.baseClasses) accu1 else dominators(rest, accu1)
142142
case Nil => // this case can happen because after erasure we do not have a top class anymore
143-
assert(ctx.erasedTypes)
143+
assert(ctx.erasedTypes || ctx.reporter.errorsReported)
144144
defn.ObjectClass :: Nil
145145
}
146146

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

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,12 @@ object Types {
142142
/** Is this type a value type? */
143143
final def isValueType: Boolean = this.isInstanceOf[ValueType]
144144

145-
/** Is the is value type or type lambda? */
145+
/** Is this a value type or a type lambda? */
146146
final def isValueTypeOrLambda: Boolean = isValueType || this.isInstanceOf[TypeLambda]
147147

148+
/** Is this a value type or a wildcard? */
149+
final def isValueTypeOrWildcard: Boolean = isValueType || this.isInstanceOf[WildcardType]
150+
148151
/** Does this type denote a stable reference (i.e. singleton type)? */
149152
final def isStable(implicit ctx: Context): Boolean = stripTypeVar match {
150153
case tp: TermRef => tp.termSymbol.isStable && tp.prefix.isStable || tp.info.isStable
@@ -589,13 +592,14 @@ object Types {
589592

590593
def goRefined(tp: RefinedType) = {
591594
val pdenot = go(tp.parent)
595+
val pinfo = pdenot.info
592596
val rinfo = tp.refinedInfo
593-
if (name.isTypeName) { // simplified case that runs more efficiently
597+
if (name.isTypeName && !pinfo.isInstanceOf[ClassInfo]) { // simplified case that runs more efficiently
594598
val jointInfo =
595599
if (rinfo.isAlias) rinfo
596-
else if (pdenot.info.isAlias) pdenot.info
597-
else if (ctx.pendingMemberSearches.contains(name)) pdenot.info safe_& rinfo
598-
else pdenot.info recoverable_& rinfo
600+
else if (pinfo.isAlias) pinfo
601+
else if (ctx.pendingMemberSearches.contains(name)) pinfo safe_& rinfo
602+
else pinfo recoverable_& rinfo
599603
pdenot.asSingleDenotation.derivedSingleDenotation(pdenot.symbol, jointInfo)
600604
} else {
601605
pdenot & (
@@ -1523,11 +1527,8 @@ object Types {
15231527
/** A marker trait for types that can be types of values or prototypes of value types */
15241528
trait ValueTypeOrProto extends TermType
15251529

1526-
/** A marker trait for types that can be types of values or wildcards */
1527-
trait ValueTypeOrWildcard extends TermType
1528-
15291530
/** A marker trait for types that can be types of values or that are higher-kinded */
1530-
trait ValueType extends ValueTypeOrProto with ValueTypeOrWildcard
1531+
trait ValueType extends ValueTypeOrProto
15311532

15321533
/** A marker trait for types that are guaranteed to contain only a
15331534
* single non-null value (they might contain null in addition).
@@ -2479,8 +2480,8 @@ object Types {
24792480

24802481
object AndType {
24812482
def apply(tp1: Type, tp2: Type)(implicit ctx: Context): AndType = {
2482-
assert(tp1.isInstanceOf[ValueTypeOrWildcard] &&
2483-
tp2.isInstanceOf[ValueTypeOrWildcard], i"$tp1 & $tp2 / " + s"$tp1 & $tp2")
2483+
assert(tp1.isValueTypeOrWildcard &&
2484+
tp2.isValueTypeOrWildcard, i"$tp1 & $tp2 / " + s"$tp1 & $tp2")
24842485
unchecked(tp1, tp2)
24852486
}
24862487

@@ -2524,8 +2525,8 @@ object Types {
25242525
myBaseClasses
25252526
}
25262527

2527-
assert(tp1.isInstanceOf[ValueTypeOrWildcard] &&
2528-
tp2.isInstanceOf[ValueTypeOrWildcard], s"$tp1 $tp2")
2528+
assert(tp1.isValueTypeOrWildcard &&
2529+
tp2.isValueTypeOrWildcard, s"$tp1 $tp2")
25292530

25302531
private[this] var myJoin: Type = _
25312532
private[this] var myJoinPeriod: Period = Nowhere
@@ -3477,7 +3478,7 @@ object Types {
34773478
if (selfTypeCache == null)
34783479
selfTypeCache = {
34793480
val given = cls.givenSelfType
3480-
if (!given.exists) appliedRef
3481+
if (!given.isValueType) appliedRef
34813482
else if (cls is Module) given
34823483
else if (ctx.erasedTypes) appliedRef
34833484
else AndType(given, appliedRef)
@@ -3756,7 +3757,7 @@ object Types {
37563757
object TryDynamicCallType extends FlexType
37573758

37583759
/** Wildcard type, possibly with bounds */
3759-
abstract case class WildcardType(optBounds: Type) extends CachedGroundType with ValueTypeOrWildcard {
3760+
abstract case class WildcardType(optBounds: Type) extends CachedGroundType with TermType {
37603761
def derivedWildcardType(optBounds: Type)(implicit ctx: Context) =
37613762
if (optBounds eq this.optBounds) this
37623763
else if (!optBounds.exists) WildcardType

compiler/src/dotty/tools/dotc/transform/CheckReentrant.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class CheckReentrant extends MiniPhase {
8282
}
8383
}
8484
for (parent <- cls.classInfo.classParents)
85-
addVars(parent.typeSymbol.asClass)
85+
addVars(parent.classSymbol.asClass)
8686
}
8787
}
8888
}

compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ object GenericSignatures {
5353
val validParents =
5454
if (isTraitSignature)
5555
// java is unthrilled about seeing interfaces inherit from classes
56-
minParents filter (p => isInterfaceOrTrait(p.typeSymbol))
56+
minParents filter (p => isInterfaceOrTrait(p.classSymbol))
5757
else minParents
5858

5959
val ps = ensureClassAsFirstParent(validParents)
@@ -329,11 +329,11 @@ object GenericSignatures {
329329
def isUnshadowed(psym: Symbol) =
330330
!(psyms exists (qsym => (psym ne qsym) && (qsym isSubClass psym)))
331331
val cs = parents.iterator.filter { p => // isUnshadowed is a bit expensive, so try classes first
332-
val psym = p.typeSymbol
332+
val psym = p.classSymbol
333333
psym.ensureCompleted()
334334
psym.isClass && !psym.is(Trait) && isUnshadowed(psym)
335335
}
336-
(if (cs.hasNext) cs else parents.iterator.filter(p => isUnshadowed(p.typeSymbol))).next()
336+
(if (cs.hasNext) cs else parents.iterator.filter(p => isUnshadowed(p.classSymbol))).next()
337337
}
338338
}
339339
}

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

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -879,19 +879,25 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
879879
*/
880880
def trySelectUnapply(qual: untpd.Tree)(fallBack: Tree => Tree): Tree = {
881881
// try first for non-overloaded, then for overloaded ocurrences
882-
def tryWithName(name: TermName)(fallBack: Tree => Tree)(implicit ctx: Context): Tree =
883-
tryEither { implicit ctx =>
884-
val specificProto = new UnapplyFunProto(selType, this)
885-
typedExpr(untpd.Select(qual, name), specificProto)
882+
def tryWithName(name: TermName)(fallBack: Tree => Tree)(implicit ctx: Context): Tree = {
883+
def tryWithProto(pt: Type)(implicit ctx: Context) = {
884+
val result = typedExpr(untpd.Select(qual, name), new UnapplyFunProto(pt, this))
885+
if (!result.symbol.exists || result.symbol.name == name) result
886+
else notAnExtractor(result)
887+
// It might be that the result of typedExpr is an `apply` selection or implicit conversion.
888+
// Reject in this case.
889+
}
890+
tryEither {
891+
implicit ctx => tryWithProto(selType)
886892
} {
887893
(sel, _) =>
888-
tryEither { implicit ctx =>
889-
val genericProto = new UnapplyFunProto(WildcardType, this)
890-
typedExpr(untpd.Select(qual, name), genericProto)
894+
tryEither {
895+
implicit ctx => tryWithProto(WildcardType)
891896
} {
892897
(_, _) => fallBack(sel)
893898
}
894899
}
900+
}
895901
// try first for unapply, then for unapplySeq
896902
tryWithName(nme.unapply) {
897903
sel => tryWithName(nme.unapplySeq)(_ => fallBack(sel)) // for backwards compatibility; will be dropped
@@ -967,7 +973,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
967973
case Apply(Apply(unapply, `dummyArg` :: Nil), args2) => assert(args2.nonEmpty); args2
968974
case Apply(unapply, `dummyArg` :: Nil) => Nil
969975
case Inlined(u, _, _) => unapplyImplicits(u)
970-
case _ => assert(ctx.reporter.errorsReported); Nil
976+
case _ => Nil.assertingErrorsReported
971977
}
972978

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

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ trait ImplicitRunInfo { self: Run =>
449449
comps += companion.asSeenFrom(pre, compSym.owner).asInstanceOf[TermRef]
450450
}
451451
def addParentScope(parent: Type): Unit =
452-
iscopeRefs(tp.baseType(parent.typeSymbol)) foreach addRef
452+
iscopeRefs(tp.baseType(parent.classSymbol)) foreach addRef
453453
val companion = cls.companionModule
454454
if (companion.exists) addRef(companion.termRef)
455455
cls.classParents foreach addParentScope

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,8 @@ object NamerContextOps {
164164
/** Find moduleClass/sourceModule in effective scope */
165165
private def findModuleBuddy(name: Name, scope: Scope)(implicit ctx: Context) = {
166166
val it = scope.lookupAll(name).filter(_ is Module)
167-
assert(it.hasNext, s"no companion $name in $scope")
168-
it.next()
167+
if (it.hasNext) it.next()
168+
else NoSymbol.assertingErrorsReported(s"no companion $name in $scope")
169169
}
170170
}
171171

@@ -918,8 +918,7 @@ class Namer { typer: Typer =>
918918
fullyDefinedType(typedAheadExpr(parent).tpe, "class parent", parent.pos)
919919
}
920920
case _ =>
921-
assert(ctx.reporter.errorsReported)
922-
UnspecifiedErrorType
921+
UnspecifiedErrorType.assertingErrorsReported
923922
}
924923
}
925924

@@ -1033,8 +1032,9 @@ class Namer { typer: Typer =>
10331032
*/
10341033
def moduleValSig(sym: Symbol)(implicit ctx: Context): Type = {
10351034
val clsName = sym.name.moduleClassName
1036-
val cls = ctx.denotNamed(clsName) suchThat (_ is ModuleClass)
1037-
ctx.owner.thisType select (clsName, cls)
1035+
val cls = ctx.denotNamed(clsName).suchThat(_ is ModuleClass)
1036+
.orElse(ctx.newStubSymbol(ctx.owner, clsName).assertingErrorsReported)
1037+
ctx.owner.thisType.select(clsName, cls)
10381038
}
10391039

10401040
/** The type signature of a ValDef or DefDef

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -472,16 +472,18 @@ object ProtoTypes {
472472
}
473473

474474
/** Create a new TypeVar that represents a dependent method parameter singleton */
475-
def newDepTypeVar(tp: Type)(implicit ctx: Context): TypeVar =
475+
def newDepTypeVar(tp: Type)(implicit ctx: Context): TypeVar = {
476476
newTypeVar(TypeBounds.upper(AndType(tp.widenExpr, defn.SingletonClass.typeRef)))
477-
477+
}
478478
/** The result type of `mt`, where all references to parameters of `mt` are
479479
* replaced by either wildcards (if typevarsMissContext) or TypeParamRefs.
480480
*/
481481
def resultTypeApprox(mt: MethodType)(implicit ctx: Context): Type =
482482
if (mt.isResultDependent) {
483483
def replacement(tp: Type) =
484-
if (ctx.mode.is(Mode.TypevarsMissContext)) WildcardType else newDepTypeVar(tp)
484+
if (ctx.mode.is(Mode.TypevarsMissContext) ||
485+
!tp.widenExpr.isValueTypeOrWildcard) WildcardType
486+
else newDepTypeVar(tp)
485487
mt.resultType.substParams(mt, mt.paramInfos.map(replacement))
486488
}
487489
else mt.resultType

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ object RefChecks {
103103
cls.pos)
104104
}
105105
for (parent <- cinfo.classParents)
106-
checkSelfConforms(parent.typeSymbol.asClass, "illegal inheritance", "parent")
106+
checkSelfConforms(parent.classSymbol.asClass, "illegal inheritance", "parent")
107107
for (reqd <- cinfo.cls.givenSelfType.classSymbols)
108108
checkSelfConforms(reqd, "missing requirement", "required")
109109
case _ =>

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

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,7 +1447,9 @@ class Typer extends Namer
14471447
assignType(cpy.TypeDef(tdef)(name, rhs1), sym)
14481448
}
14491449

1450-
def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context) = track("typedClassDef") {
1450+
def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context): Tree = track("typedClassDef") {
1451+
if (!cls.info.isInstanceOf[ClassInfo]) return EmptyTree.assertingErrorsReported
1452+
14511453
val TypeDef(name, impl @ Template(constr, parents, self, _)) = cdef
14521454
val superCtx = ctx.superCallContext
14531455

@@ -1622,16 +1624,16 @@ class Typer extends Namer
16221624
def typedPackageDef(tree: untpd.PackageDef)(implicit ctx: Context): Tree = track("typedPackageDef") {
16231625
val pid1 = typedExpr(tree.pid, AnySelectionProto)(ctx.addMode(Mode.InPackageClauseName))
16241626
val pkg = pid1.symbol
1625-
1626-
// Package will not exist if a duplicate type has already been entered, see
1627-
// `tests/neg/1708.scala`, else branch's error message should be supressed
1628-
if (pkg.exists) {
1629-
if (!pkg.is(Package)) ctx.error(PackageNameAlreadyDefined(pkg), tree.pos)
1630-
val packageCtx = ctx.packageContext(tree, pkg)
1631-
val stats1 = typedStats(tree.stats, pkg.moduleClass)(packageCtx)
1632-
cpy.PackageDef(tree)(pid1.asInstanceOf[RefTree], stats1) withType pkg.termRef
1627+
pid1 match {
1628+
case pid1: RefTree if pkg.exists =>
1629+
if (!pkg.is(Package)) ctx.error(PackageNameAlreadyDefined(pkg), tree.pos)
1630+
val packageCtx = ctx.packageContext(tree, pkg)
1631+
val stats1 = typedStats(tree.stats, pkg.moduleClass)(packageCtx)
1632+
cpy.PackageDef(tree)(pid1, stats1).withType(pkg.termRef)
1633+
case _ =>
1634+
// Package will not exist if a duplicate type has already been entered, see `tests/neg/1708.scala`
1635+
errorTree(tree, i"package ${tree.pid.name} does not exist")
16331636
}
1634-
else errorTree(tree, i"package ${tree.pid.name} does not exist")
16351637
}
16361638

16371639
def typedAnnotated(tree: untpd.Annotated, pt: Type)(implicit ctx: Context): Tree = track("typedAnnotated") {

0 commit comments

Comments
 (0)