WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1629,9 +1629,22 @@ class Namer { typer: Typer =>
def typedParentType(tree: untpd.Tree): tpd.Tree =
val parentTpt = typer.typedType(parent, AnyTypeConstructorProto)
val ptpe = parentTpt.tpe.dealias.etaCollapse
if ptpe.typeParams.nonEmpty
&& ptpe.underlyingClassRef(refinementOK = false).exists
then
// Check if type params need to be inferred. This applies when:
// 1. The type has type params AND
// 2. Either it directly underlies a class (for class/trait refs), OR
// it's a HKTypeLambda whose result is a class application and params appear in result
// (the latter handles type aliases like `type Foo[T] = Bar[T]` but not
// type-lambda-as-result cases like `type Foo[X] = [Z] =>> Bar[X]`)
val needsTypeParamInference = ptpe.typeParams.nonEmpty && (
ptpe.underlyingClassRef(refinementOK = false).exists
|| (ptpe match
case tl: HKTypeLambda =>
tl.paramRefs.exists(pref => tl.resType.existsPart(_ == pref))
&& !tl.resType.isInstanceOf[TypeLambda]
&& tl.resType.underlyingClassRef(refinementOK = false).exists
case _ => false)
)
if needsTypeParamInference then
// Try to infer type parameters from a synthetic application.
// This might yield new info if implicit parameters are resolved.
// A test case is i16778.scala.
Expand Down
32 changes: 31 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,36 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
else tree1
}

/** Type a parent type reference in `new T { ... }` expressions.
* This handles type aliases that need type parameter inference
* by creating a synthetic constructor application, similar to
* how class parents are handled in Namer.
*/
def typedNewTemplateParent(tree: untpd.Tree, pt: Type)(using Context): Tree =
// Type with AnyTypeConstructorProto to detect type aliases (HKTypeLambda)
val parentTpt = typedType(tree, AnyTypeConstructorProto)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure myself whether this is a great idea performance-wise

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried to avoid retyping in next commit

val ptpe = parentTpt.tpe.dealias

ptpe match
case tl: HKTypeLambda
// Only handle type aliases where params appear in result (not type-lambda-as-result cases)
if tl.paramRefs.exists(pref => tl.resType.existsPart(_ == pref))
&& !tl.resType.isInstanceOf[TypeLambda]
&& tl.resType.underlyingClassRef(refinementOK = false).exists =>
// Found a type alias with type params whose result underlies a class.
// Create a synthetic constructor application to infer type arguments.
val app = untpd.Apply(untpd.Select(untpd.New(parentTpt), nme.CONSTRUCTOR), Nil)
val typedApp = typedExpr(app, pt)
TypeTree(typedApp.tpe).withSpan(tree.span)
case _ =>
// For regular class/trait references, reuse the typed tree.
// If type has params but isn't a TypeLambda, eta-expand for inferTypeParams.
val resultTpe = parentTpt.tpe
if resultTpe.typeParams.nonEmpty && !resultTpe.isInstanceOf[TypeLambda] then
inferTypeParams(parentTpt.withType(resultTpe.etaExpand), pt)
else
inferTypeParams(parentTpt, pt)

def typedNew(tree: untpd.New, pt: Type)(using Context): Tree =
tree.tpt match {
case templ: untpd.Template =>
Expand All @@ -1248,7 +1278,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
then
templ1 = cpy.Template(templ)(parents = untpd.TypeTree(pt) :: Nil)
for case parent: RefTree <- templ1.parents do
typedAhead(parent, tree => inferTypeParams(typedType(tree), pt))
typedAhead(parent, typedNewTemplateParent(_, pt))
val anon = tpnme.ANON_CLASS
val clsDef = TypeDef(anon, templ1).withFlags(Final | Synthetic)
typed(
Expand Down
15 changes: 15 additions & 0 deletions tests/pos/i19745.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
final abstract class ForcedRecompilationToken[T]
object ForcedRecompilationToken {
implicit def default: ForcedRecompilationToken["abc"] = null
}

object x {
abstract class GoodNoParens[T](implicit ev: ForcedRecompilationToken[T])
}
type BadNoParens[T] = x.GoodNoParens[T]

object App extends App {
new BadNoParens {}
new BadNoParens() {}
new x.GoodNoParens {}
}
10 changes: 10 additions & 0 deletions tests/pos/i19745b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
object x {
trait GoodNoParens[T]
}
export x.GoodNoParens as BadNoParens

object App extends App {
new BadNoParens {}
new BadNoParens() {}
new x.GoodNoParens {}
}
Loading