Skip to content

Commit 00c51d5

Browse files
committed
Better type inference for new
For an expression of the form `new { ... }`, infer the parent type if possible from the expected type. Fallback to `Object` if the expected type is undefined or is illegal for a class parent.
1 parent 9a28005 commit 00c51d5

File tree

3 files changed

+25
-9
lines changed

3 files changed

+25
-9
lines changed

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,13 +443,18 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
443443
tree.tpt match {
444444
case templ: untpd.Template =>
445445
import untpd._
446-
templ.parents foreach {
446+
var templ1 = templ
447+
if (templ1.parents.isEmpty &&
448+
isFullyDefined(pt, ForceDegree.noBottom) &&
449+
pt.underlyingClassRef(refinementOK = false).exists)
450+
templ1 = cpy.Template(templ)(parents = untpd.TypeTree(pt) :: Nil)
451+
templ1.parents foreach {
447452
case parent: RefTree =>
448453
typedAheadImpl(parent, tree => inferTypeParams(typedType(tree), pt))
449454
case _ =>
450455
}
451456
val x = tpnme.ANON_CLASS
452-
val clsDef = TypeDef(x, templ).withFlags(Final)
457+
val clsDef = TypeDef(x, templ1).withFlags(Final)
453458
typed(cpy.Block(tree)(clsDef :: Nil, New(Ident(x), Nil)), pt)
454459
case _ =>
455460
var tpt1 = typedType(tree.tpt)

docs/docs/reference/implicit-by-name-parameters.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,22 @@
33
Call-by-name implicit parameters can be used to avoid a divergent implicit expansion.
44

55
```scala
6-
trait Serializable[T] {
6+
trait Codec[T] {
77
def write(x: T): Unit
88
}
99

10-
implicit def serializeInt: Serializable[Int] = ???
10+
implicit def intCodec: Codec[Int] = ???
1111

12-
implicit def serializeOption[T](implicit ev: => Serializable[T]): Serializable[Option[T]] =
13-
new Serializable[Option[T]] {
12+
implicit def optionCodec[T]
13+
(implicit ev: => Codec[T]): Codec[Option[T]] =
14+
new {
1415
def write(xo: Option[T]) = xo match {
1516
case Some(x) => ev.write(x)
1617
case None =>
1718
}
1819
}
1920

20-
val s = implicitly[Serializable[Option[Int]]]
21+
val s = implicitly[Codec[Option[Int]]]
2122

2223
s.write(Some(33))
2324
s.write(None)
@@ -53,8 +54,8 @@ The precise steps for constructing an implicit argument for a by-name parameter
5354
In the example above, the definition of `s` would be expanded as follows.
5455

5556
```scala
56-
val s = implicitly[Test.Serializable[Option[Int]]](
57-
serializeOption[Int](serializeInt))
57+
val s = implicitly[Test.Codec[Option[Int]]](
58+
optionCodec[Int](intCodec))
5859
```
5960

6061
No lazy val was generated because the synthesized argument is not recursive.

tests/pos/news.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
object Test {
2+
3+
abstract class C[T] { def f: T }
4+
5+
val x: C[Int] = new { def f = 2 }
6+
7+
val y = new { val name = "Bob" }
8+
9+
10+
}

0 commit comments

Comments
 (0)