Skip to content

Commit 8b4b608

Browse files
committed
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 79d9a6f commit 8b4b608

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
@@ -3326,25 +3326,23 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
33263326
// try an implicit conversion or given extension
33273327
if ctx.mode.is(Mode.ImplicitsEnabled) && !tree.name.isConstructorName && qual.tpe.isValueType then
33283328
try
3329-
trace(i"try insert impl on qualifier $tree $pt") {
3330-
val selProto = selectionProto
3331-
inferView(qual, selProto) match
3332-
case SearchSuccess(found, _, _, isExtension) =>
3333-
if isExtension then return found
3334-
else
3335-
checkImplicitConversionUseOK(found)
3336-
return withoutMode(Mode.ImplicitsEnabled)(typedSelect(tree, pt, found))
3337-
case failure: SearchFailure =>
3338-
if failure.isAmbiguous then
3339-
return
3340-
if !inSelect // in a selection we will do the canDefineFurther afterwards
3341-
&& canDefineFurther(qual.tpe.widen)
3342-
then
3343-
tryExtensionOrConversion(tree, pt, mbrProto, qual, locked, compat, inSelect)
3344-
else
3345-
err.typeMismatch(qual, selProto, failure.reason) // TODO: report NotAMember instead, but need to be aware of failure
3346-
rememberSearchFailure(qual, failure)
3347-
}
3329+
val selProto = selectionProto
3330+
trace(i"try insert impl on qualifier $tree $pt") { inferView(qual, selProto) } match
3331+
case SearchSuccess(found, _, _, isExtension) =>
3332+
if isExtension then return found
3333+
else
3334+
checkImplicitConversionUseOK(found)
3335+
return withoutMode(Mode.ImplicitsEnabled)(typedSelect(tree, pt, found))
3336+
case failure: SearchFailure =>
3337+
if failure.isAmbiguous then
3338+
return
3339+
if !inSelect // in a selection we will do the canDefineFurther afterwards
3340+
&& canDefineFurther(qual.tpe.widen)
3341+
then
3342+
tryExtensionOrConversion(tree, pt, mbrProto, qual, locked, compat, inSelect)
3343+
else
3344+
err.typeMismatch(qual, selProto, failure.reason) // TODO: report NotAMember instead, but need to be aware of failure
3345+
rememberSearchFailure(qual, failure)
33483346
catch case ex: TypeError => nestedFailure(ex)
33493347

33503348
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)