Skip to content

Commit 5f1a8de

Browse files
Merge pull request #2547 from dotty-staging/fix-#2492
Fix #2492: Avoid typing the body when self has error type
2 parents 8b0aca2 + 4dfda04 commit 5f1a8de

File tree

5 files changed

+55
-33
lines changed

5 files changed

+55
-33
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.exists) 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: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,44 +1321,49 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
13211321
val parentsWithClass = ensureFirstIsClass(parents mapconserve typedParent, cdef.namePos)
13221322
val parents1 = ensureConstrCall(cls, parentsWithClass)(superCtx)
13231323
val self1 = typed(self)(ctx.outer).asInstanceOf[ValDef] // outer context where class members are not visible
1324-
val dummy = localDummy(cls, impl)
1325-
val body1 = typedStats(impl.body, dummy)(inClassContext(self1.symbol))
1326-
cls.setNoInitsFlags((NoInitsInterface /: body1)((fs, stat) => fs & defKind(stat)))
1327-
1328-
// Expand comments and type usecases
1329-
cookComments(body1.map(_.symbol), self1.symbol)(localContext(cdef, cls).setNewScope)
1330-
1331-
checkNoDoubleDefs(cls)
1332-
val impl1 = cpy.Template(impl)(constr1, parents1, self1, body1)
1333-
.withType(dummy.nonMemberTermRef)
1334-
checkVariance(impl1)
1335-
if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) checkRealizableBounds(cls.typeRef, cdef.namePos)
1336-
val cdef1 = assignType(cpy.TypeDef(cdef)(name, impl1), cls)
1337-
if (ctx.phase.isTyper && cdef1.tpe.derivesFrom(defn.DynamicClass) && !ctx.dynamicsEnabled) {
1338-
val isRequired = parents1.exists(_.tpe.isRef(defn.DynamicClass))
1339-
ctx.featureWarning(nme.dynamics.toString, "extension of type scala.Dynamic", isScala2Feature = true,
1324+
if (self1.tpt.tpe.isError) {
1325+
// fail fast to avoid typing the body with an error type
1326+
cdef.withType(UnspecifiedErrorType)
1327+
} else {
1328+
val dummy = localDummy(cls, impl)
1329+
val body1 = typedStats(impl.body, dummy)(inClassContext(self1.symbol))
1330+
cls.setNoInitsFlags((NoInitsInterface /: body1) ((fs, stat) => fs & defKind(stat)))
1331+
1332+
// Expand comments and type usecases
1333+
cookComments(body1.map(_.symbol), self1.symbol)(localContext(cdef, cls).setNewScope)
1334+
1335+
checkNoDoubleDefs(cls)
1336+
val impl1 = cpy.Template(impl)(constr1, parents1, self1, body1)
1337+
.withType(dummy.nonMemberTermRef)
1338+
checkVariance(impl1)
1339+
if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) checkRealizableBounds(cls.typeRef, cdef.namePos)
1340+
val cdef1 = assignType(cpy.TypeDef(cdef)(name, impl1), cls)
1341+
if (ctx.phase.isTyper && cdef1.tpe.derivesFrom(defn.DynamicClass) && !ctx.dynamicsEnabled) {
1342+
val isRequired = parents1.exists(_.tpe.isRef(defn.DynamicClass))
1343+
ctx.featureWarning(nme.dynamics.toString, "extension of type scala.Dynamic", isScala2Feature = true,
13401344
cls, isRequired, cdef.pos)
1341-
}
1345+
}
13421346

1343-
// Check that phantom lattices are defined in a static object
1344-
if (cls.classParents.exists(_.classSymbol eq defn.PhantomClass) && !cls.isStaticOwner)
1345-
ctx.error("only static objects can extend scala.Phantom", cdef.pos)
1347+
// Check that phantom lattices are defined in a static object
1348+
if (cls.classParents.exists(_.classSymbol eq defn.PhantomClass) && !cls.isStaticOwner)
1349+
ctx.error("only static objects can extend scala.Phantom", cdef.pos)
13461350

1347-
// check value class constraints
1348-
checkDerivedValueClass(cls, body1)
1351+
// check value class constraints
1352+
checkDerivedValueClass(cls, body1)
13491353

1350-
if (ctx.settings.YretainTrees.value) {
1351-
cls.myTree = cdef1
1354+
if (ctx.settings.YretainTrees.value) {
1355+
cls.myTree = cdef1
1356+
}
1357+
cdef1
1358+
1359+
// todo later: check that
1360+
// 1. If class is non-abstract, it is instantiatable:
1361+
// - self type is s supertype of own type
1362+
// - all type members have consistent bounds
1363+
// 2. all private type members have consistent bounds
1364+
// 3. Types do not override classes.
1365+
// 4. Polymorphic type defs override nothing.
13521366
}
1353-
cdef1
1354-
1355-
// todo later: check that
1356-
// 1. If class is non-abstract, it is instantiatable:
1357-
// - self type is s supertype of own type
1358-
// - all type members have consistent bounds
1359-
// 2. all private type members have consistent bounds
1360-
// 3. Types do not override classes.
1361-
// 4. Polymorphic type defs override nothing.
13621367
}
13631368

13641369
/** 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)