diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 6b94fbfd7595..3ebbf42335bb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -892,8 +892,17 @@ trait Applications extends Compatibility { def typedApply(tree: untpd.Apply, pt: Type)(using Context): Tree = { def realApply(using Context): Tree = { + val resultProto = tree.fun match + case Select(New(_), _) if pt.isInstanceOf[ValueType] => pt + // Don't ignore expected value types of `new` expressions. If we have a `new C()` + // with expected type `C[T]` we want to use the type to instantiate `C` + // immediately. This is necessary since `C` might _also_ have using clauses + // that we want to instantiate with the best available type. See i15664.scala. + case _ => IgnoredProto(pt) + // Do ignore other expected result types, since there might be an implicit conversion + // on the result. We could drop this if we disallow unrestricted implicit conversions. val originalProto = - new FunProto(tree.args, IgnoredProto(pt))(this, tree.applyKind)(using argCtx(tree)) + new FunProto(tree.args, resultProto)(this, tree.applyKind)(using argCtx(tree)) record("typedApply") val fun1 = typedExpr(tree.fun, originalProto) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 3aacd6659b79..b0316113e837 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3346,25 +3346,23 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer // try an implicit conversion or given extension if ctx.mode.is(Mode.ImplicitsEnabled) && !tree.name.isConstructorName && qual.tpe.isValueType then try - trace(i"try insert impl on qualifier $tree $pt") { - val selProto = selectionProto - inferView(qual, selProto) match - case SearchSuccess(found, _, _, isExtension) => - if isExtension then return found - else - checkImplicitConversionUseOK(found) - return withoutMode(Mode.ImplicitsEnabled)(typedSelect(tree, pt, found)) - case failure: SearchFailure => - if failure.isAmbiguous then - return - if !inSelect // in a selection we will do the canDefineFurther afterwards - && canDefineFurther(qual.tpe.widen) - then - tryExtensionOrConversion(tree, pt, mbrProto, qual, locked, compat, inSelect) - else - err.typeMismatch(qual, selProto, failure.reason) // TODO: report NotAMember instead, but need to be aware of failure - rememberSearchFailure(qual, failure) - } + val selProto = selectionProto + trace(i"try insert impl on qualifier $tree $pt") { inferView(qual, selProto) } match + case SearchSuccess(found, _, _, isExtension) => + if isExtension then return found + else + checkImplicitConversionUseOK(found) + return withoutMode(Mode.ImplicitsEnabled)(typedSelect(tree, pt, found)) + case failure: SearchFailure => + if failure.isAmbiguous then + return + if !inSelect // in a selection we will do the canDefineFurther afterwards + && canDefineFurther(qual.tpe.widen) + then + tryExtensionOrConversion(tree, pt, mbrProto, qual, locked, compat, inSelect) + else + err.typeMismatch(qual, selProto, failure.reason) // TODO: report NotAMember instead, but need to be aware of failure + rememberSearchFailure(qual, failure) catch case ex: TypeError => nestedFailure(ex) EmptyTree diff --git a/tests/pos/i15664.scala b/tests/pos/i15664.scala new file mode 100644 index 000000000000..7db8fe8cf23f --- /dev/null +++ b/tests/pos/i15664.scala @@ -0,0 +1,25 @@ +trait CpsMonad[F[_]]: + type Context <: CpsMonadContext[F] +type Aux[F[_], C <: CpsMonadContext[F]] = CpsMonad[F] { type Context = C } +trait CpsMonadContext[F[_]] +trait CpsMonadInstanceContext[F[_]] extends CpsMonad[F]: + type Context = CpsMonadInstanceContextBody[F] +class CpsMonadInstanceContextBody[F[_]](m: CpsMonadInstanceContext[F]) extends CpsMonadContext[F] +class InferAsyncArg[F[_], C <: CpsMonadContext[F]](using val am: Aux[F, C]) + +sealed abstract class ZManaged[-R, +E, +A] +type RManaged[-R, +A] = ZManaged[R, Throwable, A] + +type ForZManaged[R, E] = [X] =>> ZManaged[R, E, X] +given zManagedCpsMonad[R, E]: CpsMonadInstanceContext[ForZManaged[R, E]] = ??? + +// Usage +def failing[R, E](using + CpsMonad[ForZManaged[R, E]] +): InferAsyncArg[ForZManaged[R, E], CpsMonadInstanceContextBody[ForZManaged[R, E]]] = + new InferAsyncArg() + +def compiling[R, E](using + CpsMonad[ForZManaged[R, E]] +) = + new InferAsyncArg[ForZManaged[R, E], CpsMonadInstanceContextBody[ForZManaged[R, E]]]