Skip to content

Commit 6acd7bf

Browse files
oderskyKordyjan
authored andcommitted
Don't ignore expected types of New.
A problem arises if we typecheck an expression like `new C()` with expected type `C[U]` where `C` is defined like this ```scala class C[X](using X)() ``` In this case, we'd like to propagate `U` as the type instance of `X` before we resolve the using clause. To do this, we have to keep the expected result type `C[X]` for typechecking the function part `new C`. Previously, that type was wrapped in an IgnoredProto. The problem was detected now since a class C with just the using clause and no empty parameter clause was previously expanded to ```scala class C[X]()(using X) ``` but is now expanded to ```scala class C[X](using X)() ``` Under the previous expansion, we type checked and `new C()` before looking for an argument of the using clause, so the problem did not arise.
1 parent 9fa1f48 commit 6acd7bf

File tree

3 files changed

+52
-20
lines changed

3 files changed

+52
-20
lines changed

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -892,8 +892,17 @@ trait Applications extends Compatibility {
892892
def typedApply(tree: untpd.Apply, pt: Type)(using Context): Tree = {
893893

894894
def realApply(using Context): Tree = {
895+
val resultProto = tree.fun match
896+
case Select(New(_), _) => pt
897+
// Don't ignore expected types of `new` expressions. If we have a `new C()`
898+
// with expected type `C[T]` we want to use the type to instantiate `C`
899+
// immediately. This is necessary since `C` might _also_ have using clauses
900+
// that we want to instantiate with the best available type. See i15664.scala.
901+
case _ => IgnoredProto(pt)
902+
// Do ignore other expected result types, since there might be an implicit conversion
903+
// on the result. We could drop this if we disallow unrestricted implicit conversions.
895904
val originalProto =
896-
new FunProto(tree.args, IgnoredProto(pt))(this, tree.applyKind)(using argCtx(tree))
905+
new FunProto(tree.args, resultProto)(this, tree.applyKind)(using argCtx(tree))
897906
record("typedApply")
898907
val fun1 = typedExpr(tree.fun, originalProto)
899908

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

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3304,25 +3304,23 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
33043304
// try an implicit conversion or given extension
33053305
if ctx.mode.is(Mode.ImplicitsEnabled) && !tree.name.isConstructorName && qual.tpe.isValueType then
33063306
try
3307-
trace(i"try insert impl on qualifier $tree $pt") {
3308-
val selProto = selectionProto
3309-
inferView(qual, selProto) match
3310-
case SearchSuccess(found, _, _, isExtension) =>
3311-
if isExtension then return found
3312-
else
3313-
checkImplicitConversionUseOK(found)
3314-
return withoutMode(Mode.ImplicitsEnabled)(typedSelect(tree, pt, found))
3315-
case failure: SearchFailure =>
3316-
if failure.isAmbiguous then
3317-
return
3318-
if !inSelect // in a selection we will do the canDefineFurther afterwards
3319-
&& canDefineFurther(qual.tpe.widen)
3320-
then
3321-
tryExtensionOrConversion(tree, pt, mbrProto, qual, locked, compat, inSelect)
3322-
else
3323-
err.typeMismatch(qual, selProto, failure.reason) // TODO: report NotAMember instead, but need to be aware of failure
3324-
rememberSearchFailure(qual, failure)
3325-
}
3307+
val selProto = selectionProto
3308+
trace(i"try insert impl on qualifier $tree $pt") { inferView(qual, selProto) } match
3309+
case SearchSuccess(found, _, _, isExtension) =>
3310+
if isExtension then return found
3311+
else
3312+
checkImplicitConversionUseOK(found)
3313+
return withoutMode(Mode.ImplicitsEnabled)(typedSelect(tree, pt, found))
3314+
case failure: SearchFailure =>
3315+
if failure.isAmbiguous then
3316+
return
3317+
if !inSelect // in a selection we will do the canDefineFurther afterwards
3318+
&& canDefineFurther(qual.tpe.widen)
3319+
then
3320+
tryExtensionOrConversion(tree, pt, mbrProto, qual, locked, compat, inSelect)
3321+
else
3322+
err.typeMismatch(qual, selProto, failure.reason) // TODO: report NotAMember instead, but need to be aware of failure
3323+
rememberSearchFailure(qual, failure)
33263324
catch case ex: TypeError => nestedFailure(ex)
33273325

33283326
EmptyTree

tests/pos/i15664.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
trait CpsMonad[F[_]]:
2+
type Context <: CpsMonadContext[F]
3+
type Aux[F[_], C <: CpsMonadContext[F]] = CpsMonad[F] { type Context = C }
4+
trait CpsMonadContext[F[_]]
5+
trait CpsMonadInstanceContext[F[_]] extends CpsMonad[F]:
6+
type Context = CpsMonadInstanceContextBody[F]
7+
class CpsMonadInstanceContextBody[F[_]](m: CpsMonadInstanceContext[F]) extends CpsMonadContext[F]
8+
class InferAsyncArg[F[_], C <: CpsMonadContext[F]](using val am: Aux[F, C])
9+
10+
sealed abstract class ZManaged[-R, +E, +A]
11+
type RManaged[-R, +A] = ZManaged[R, Throwable, A]
12+
13+
type ForZManaged[R, E] = [X] =>> ZManaged[R, E, X]
14+
given zManagedCpsMonad[R, E]: CpsMonadInstanceContext[ForZManaged[R, E]] = ???
15+
16+
// Usage
17+
def failing[R, E](using
18+
CpsMonad[ForZManaged[R, E]]
19+
): InferAsyncArg[ForZManaged[R, E], CpsMonadInstanceContextBody[ForZManaged[R, E]]] =
20+
new InferAsyncArg()
21+
22+
def compiling[R, E](using
23+
CpsMonad[ForZManaged[R, E]]
24+
) =
25+
new InferAsyncArg[ForZManaged[R, E], CpsMonadInstanceContextBody[ForZManaged[R, E]]]

0 commit comments

Comments
 (0)