From 0a07f7f3385e5cc65fe58db753d2781ecf14ec41 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 17 Dec 2016 18:14:15 +0100 Subject: [PATCH] Infer type parameters of anonymous class parents from expected type If a parent type of an anonymous class is an Ident or Select which refers to a parameterized type, use the expected type to infer its type parameters. Fixes #1803. --- .../src/dotty/tools/dotc/typer/Inferencing.scala | 12 ++++++++++++ compiler/src/dotty/tools/dotc/typer/Namer.scala | 10 +++++----- compiler/src/dotty/tools/dotc/typer/Typer.scala | 5 +++++ tests/pos/i1803.scala | 7 +++++++ 4 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 tests/pos/i1803.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index 1cb86dd72c68..86649d78ed54 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -119,6 +119,18 @@ object Inferencing { } } + /** If `tree` has a PolyType, infer its type parameters by comparing with expected type `pt` */ + def inferTypeParams(tree: Tree, pt: Type)(implicit ctx: Context): Tree = tree.tpe match { + case poly: PolyType => + val (poly1, tvars) = constrained(poly, tree) + val tree1 = tree.withType(poly1).appliedToTypeTrees(tvars) + tree1.tpe <:< pt + fullyDefinedType(tree1.tpe, "template parent", tree.pos) + tree1 + case _ => + tree + } + /** The list of uninstantiated type variables bound by some prefix of type `T` which * occur in at least one formal parameter type of a prefix application. * Considered prefixes are: diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 4bcdd5071459..1b6e437b59df 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -852,23 +852,23 @@ class Namer { typer: Typer => } } - /** Typecheck tree during completion, and remember result in typedtree map */ - private def typedAheadImpl(tree: Tree, pt: Type)(implicit ctx: Context): tpd.Tree = { + /** Typecheck `tree` during completion using `typed`, and remember result in TypedAhead map */ + def typedAheadImpl(tree: Tree, typed: untpd.Tree => tpd.Tree)(implicit ctx: Context): tpd.Tree = { val xtree = expanded(tree) xtree.getAttachment(TypedAhead) match { case Some(ttree) => ttree case none => - val ttree = typer.typed(tree, pt) + val ttree = typed(tree) xtree.putAttachment(TypedAhead, ttree) ttree } } def typedAheadType(tree: Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree = - typedAheadImpl(tree, pt)(ctx retractMode Mode.PatternOrType addMode Mode.Type) + typedAheadImpl(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrType addMode Mode.Type)) def typedAheadExpr(tree: Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree = - typedAheadImpl(tree, pt)(ctx retractMode Mode.PatternOrType) + typedAheadImpl(tree, typer.typed(_, pt)(ctx retractMode Mode.PatternOrType)) def typedAheadAnnotation(tree: Tree)(implicit ctx: Context): Symbol = tree match { case Apply(fn, _) => typedAheadAnnotation(fn) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index eec3859f9700..73084bd86bbf 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -454,6 +454,11 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit tree.tpt match { case templ: untpd.Template => import untpd._ + templ.parents foreach { + case parent: RefTree => + typedAheadImpl(parent, tree => inferTypeParams(typedType(tree), pt)) + case _ => + } val x = tpnme.ANON_CLASS val clsDef = TypeDef(x, templ).withFlags(Final) typed(cpy.Block(tree)(clsDef :: Nil, New(Ident(x), Nil)), pt) diff --git a/tests/pos/i1803.scala b/tests/pos/i1803.scala new file mode 100644 index 000000000000..19bf219187f4 --- /dev/null +++ b/tests/pos/i1803.scala @@ -0,0 +1,7 @@ +class C[T] + +object Test { + def f(x: C[Int]) = ??? + + f(new C {}) +}