Skip to content

Commit 15f3558

Browse files
committed
Fix scala#2492: Avoid typing the body when self has error type
1 parent 12c2e47 commit 15f3558

File tree

5 files changed

+53
-31
lines changed

5 files changed

+53
-31
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ trait TypeAssigner {
466466
val rsym = refinement.symbol
467467
val rinfo = if (rsym is Accessor) rsym.info.resultType else rsym.info
468468
if (rinfo.isError) rinfo
469+
else if (rinfo eq NoType) parent // can happen after failure in self type definition
469470
else RefinedType(parent, rsym.name, rinfo)
470471
}
471472
val refined = (parent.tpe /: refinements)(addRefinement)

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

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,7 +1264,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
12641264
assignType(cpy.TypeDef(tdef)(name, rhs1), sym)
12651265
}
12661266

1267-
def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context) = track("typedClassDef") {
1267+
def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context): tpd.TypeDef = track("typedClassDef") {
12681268
val TypeDef(name, impl @ Template(constr, parents, self, _)) = cdef
12691269
val superCtx = ctx.superCallContext
12701270

@@ -1315,41 +1315,46 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
13151315
val parentsWithClass = ensureFirstIsClass(parents mapconserve typedParent, cdef.pos.toSynthetic)
13161316
val parents1 = ensureConstrCall(cls, parentsWithClass)(superCtx)
13171317
val self1 = typed(self)(ctx.outer).asInstanceOf[ValDef] // outer context where class members are not visible
1318-
val dummy = localDummy(cls, impl)
1319-
val body1 = typedStats(impl.body, dummy)(inClassContext(self1.symbol))
1320-
cls.setNoInitsFlags((NoInitsInterface /: body1)((fs, stat) => fs & defKind(stat)))
1321-
1322-
// Expand comments and type usecases
1323-
cookComments(body1.map(_.symbol), self1.symbol)(localContext(cdef, cls).setNewScope)
1324-
1325-
checkNoDoubleDefs(cls)
1326-
val impl1 = cpy.Template(impl)(constr1, parents1, self1, body1)
1327-
.withType(dummy.nonMemberTermRef)
1328-
checkVariance(impl1)
1329-
if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) checkRealizableBounds(cls.typeRef, cdef.namePos)
1330-
val cdef1 = assignType(cpy.TypeDef(cdef)(name, impl1), cls)
1331-
if (ctx.phase.isTyper && cdef1.tpe.derivesFrom(defn.DynamicClass) && !ctx.dynamicsEnabled) {
1332-
val isRequired = parents1.exists(_.tpe.isRef(defn.DynamicClass))
1333-
ctx.featureWarning(nme.dynamics.toString, "extension of type scala.Dynamic", isScala2Feature = true,
1318+
if (self1.tpt.tpe.isError) {
1319+
// fail fast to avoid typing the body with an error type
1320+
cdef.withType(UnspecifiedErrorType)
1321+
} else {
1322+
val dummy = localDummy(cls, impl)
1323+
val body1 = typedStats(impl.body, dummy)(inClassContext(self1.symbol))
1324+
cls.setNoInitsFlags((NoInitsInterface /: body1) ((fs, stat) => fs & defKind(stat)))
1325+
1326+
// Expand comments and type usecases
1327+
cookComments(body1.map(_.symbol), self1.symbol)(localContext(cdef, cls).setNewScope)
1328+
1329+
checkNoDoubleDefs(cls)
1330+
val impl1 = cpy.Template(impl)(constr1, parents1, self1, body1)
1331+
.withType(dummy.nonMemberTermRef)
1332+
checkVariance(impl1)
1333+
if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) checkRealizableBounds(cls.typeRef, cdef.namePos)
1334+
val cdef1 = assignType(cpy.TypeDef(cdef)(name, impl1), cls)
1335+
if (ctx.phase.isTyper && cdef1.tpe.derivesFrom(defn.DynamicClass) && !ctx.dynamicsEnabled) {
1336+
val isRequired = parents1.exists(_.tpe.isRef(defn.DynamicClass))
1337+
ctx.featureWarning(nme.dynamics.toString, "extension of type scala.Dynamic", isScala2Feature = true,
13341338
cls, isRequired, cdef.pos)
1335-
}
1339+
}
13361340

1337-
// Check that phantom lattices are defined in a static object
1338-
if (cls.classParents.exists(_.classSymbol eq defn.PhantomClass) && !cls.isStaticOwner)
1339-
ctx.error("only static objects can extend scala.Phantom", cdef.pos)
1341+
// Check that phantom lattices are defined in a static object
1342+
if (cls.classParents.exists(_.classSymbol eq defn.PhantomClass) && !cls.isStaticOwner)
1343+
ctx.error("only static objects can extend scala.Phantom", cdef.pos)
13401344

1341-
// check value class constraints
1342-
checkDerivedValueClass(cls, body1)
1345+
// check value class constraints
1346+
checkDerivedValueClass(cls, body1)
13431347

1344-
cdef1
1348+
cdef1
13451349

1346-
// todo later: check that
1347-
// 1. If class is non-abstract, it is instantiatable:
1348-
// - self type is s supertype of own type
1349-
// - all type members have consistent bounds
1350-
// 2. all private type members have consistent bounds
1351-
// 3. Types do not override classes.
1352-
// 4. Polymorphic type defs override nothing.
1350+
// todo later: check that
1351+
// 1. If class is non-abstract, it is instantiatable:
1352+
// - self type is s supertype of own type
1353+
// - all type members have consistent bounds
1354+
// 2. all private type members have consistent bounds
1355+
// 3. Types do not override classes.
1356+
// 4. Polymorphic type defs override nothing.
1357+
}
13531358
}
13541359

13551360
/** Ensure that the first type in a list of parent types Ps points to a non-trait class.

tests/neg/i2492.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class Map[K, V]
2+
object Foo {
3+
val s: Map {type Map$K = String; type Map$V = Int} = null // error
4+
}

tests/neg/i2492b.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class Map[K]
2+
object Foo {
3+
type X = Map { type Map$$K = String } // error
4+
}

tests/repl/i2492.check

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
scala> class Map[K, V]
2+
defined class Map
3+
scala> val s: Map {type Map$K =String;type Map$V = Int} = null
4+
-- [E055] Syntax Error: <console>:5:7 ------------------------------------------
5+
5 |val s: Map {type Map$K =String;type Map$V = Int} = null
6+
| ^^^
7+
|missing type parameter for [line1$object$$iw$$iw$Map$$K, line1$object$$iw$$iw$Map$$V] => Map[K, V]
8+
scala> :quit

0 commit comments

Comments
 (0)