Skip to content

Commit 648e702

Browse files
committed
Check New nodes for instantiability.
- Abstract classes cannot be instantiated (exceptions: parent news and Java annotations) - Instantiateed class must conform to its self type.
1 parent 71a5179 commit 648e702

File tree

4 files changed

+52
-5
lines changed

4 files changed

+52
-5
lines changed

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,18 +243,21 @@ trait Checking {
243243

244244
/** Check that `tp` is a class type with a stable prefix. Also:
245245
* If `traitReq` is true, check that `tp` refers to a trait.
246-
* If `concreteReq` is true, check that `tp` refers to a nonAbstract class.
246+
* If `concreteReq` is true, check that `tp` refers to a nonAbstract class
247+
* and that the instance conforms to the self type of the created class.
247248
* Stability checking is disabled in phases after RefChecks.
248249
* @return `tp` itself if it is a class or trait ref, ObjectClass.typeRef if not.
249250
*/
250251
def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean = false, concreteReq: Boolean = false)(implicit ctx: Context): Type =
251252
tp.underlyingClassRef(refinementOK = false) match {
252253
case tref: TypeRef =>
254+
val cls = tref.symbol
253255
if (ctx.phase <= ctx.refchecksPhase) checkStable(tref.prefix, pos)
254-
if (traitReq && !(tref.symbol is Trait))
256+
if (traitReq && !(cls is Trait))
255257
ctx.error(d"$tref is not a trait", pos)
256-
if (concreteReq && false && (tref.symbol is AbstractOrTrait))
257-
ctx.error(d"${tref.symbol} is abstract; cannot be instantiated, owner = ${ctx.owner}", pos)
258+
if (concreteReq) {
259+
if (cls.is(AbstractOrTrait))
260+
ctx.error(d"$cls is abstract; cannot be instantiated", pos)
258261
tp
259262
case _ =>
260263
ctx.error(d"$tp is not a class type", pos)

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,12 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
348348
typed(cpy.Block(tree)(clsDef :: Nil, New(Ident(x), Nil)), pt)
349349
case _ =>
350350
val tpt1 = typedType(tree.tpt)
351-
checkClassTypeWithStablePrefix(tpt1.tpe, tpt1.pos, concreteReq = !ctx.owner.isClass)
351+
val cls = tpt1.tpe.classSymbol
352+
val isJavaAnnot =
353+
tree.hasAttachment(AnnotNew) && cls.is(JavaDefined) && cls.isAnnotation
354+
val canBeAbstract =
355+
tree.hasAttachment(ParentNew) || isJavaAnnot || ctx.isAfterTyper
356+
checkClassTypeWithStablePrefix(tpt1.tpe, tree.pos, concreteReq = !canBeAbstract)
352357
assignType(cpy.New(tree)(tpt1), tpt1)
353358
// todo in a later phase: checkInstantiatable(cls, tpt1.pos)
354359
}

test/dotc/tests.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ class tests extends CompilerTest {
126126
@Test def neg_i0281 = compileFile(negDir, "i0281-null-primitive-conforms", xerrors = 3)
127127
@Test def neg_moduleSubtyping = compileFile(negDir, "moduleSubtyping", xerrors = 4)
128128
@Test def neg_escapingRefs = compileFile(negDir, "escapingRefs", xerrors = 2)
129+
@Test def neg_instantiateAbstract = compileFile(negDir, "instantiateAbstract", xerrors = 8)
129130
@Test def neg_selfInheritance = compileFile(negDir, "selfInheritance", xerrors = 5)
130131

131132
@Test def dotc = compileDir(dotcDir + "tools/dotc", failedOther)(allowDeepSubtypes ++ twice) // see dotc_core
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
abstract class AA
2+
3+
trait TT
4+
5+
class A { self: B =>
6+
7+
}
8+
9+
@scala.annotation.Annotation class C // error
10+
11+
class B extends A() {
12+
}
13+
14+
object Test {
15+
16+
@scala.annotation.Annotation type T = String // ok, annotations do not count as new
17+
@scala.annotation.Annotation val x = 1 // ok
18+
@scala.annotation.Annotation def f = 1 //ok
19+
20+
(1: @scala.annotation.Annotation) // ok
21+
22+
23+
new AA // error
24+
25+
new TT // error
26+
27+
new A // error
28+
29+
// the following are OK in Typer but would be caught later in RefChecks
30+
31+
new A() {}
32+
33+
new AA() {}
34+
35+
object O extends A
36+
37+
object OO extends AA
38+
}

0 commit comments

Comments
 (0)