diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index f8189fb8f9ee..46640b02c021 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -216,12 +216,11 @@ trait Applications extends Compatibility { self: Typer with Dynamic => case methType: MethodType => // apply the result type constraint, unless method type is dependent val resultApprox = resultTypeApprox(methType) - val savedConstraint = ctx.typerState.constraint if (!constrainResult(resultApprox, resultType)) if (ctx.typerState.isCommittable) // defer the problem until after the application; // it might be healed by an implicit conversion - assert(ctx.typerState.constraint eq savedConstraint) + () else fail(err.typeMismatchMsg(methType.resultType, resultType)) // match all arguments with corresponding formal parameters diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 39bd5233e7c9..32acd28fb32e 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -54,20 +54,23 @@ object ProtoTypes { /** Check that the result type of the current method * fits the given expected result type. */ - def constrainResult(mt: Type, pt: Type)(implicit ctx: Context): Boolean = pt match { - case pt: FunProto => - mt match { - case mt: MethodType => - constrainResult(resultTypeApprox(mt), pt.resultType) - case _ => - true - } - case _: ValueTypeOrProto if !disregardProto(pt) => - isCompatible(normalize(mt, pt), pt) - case pt: WildcardType if pt.optBounds.exists => - isCompatible(normalize(mt, pt), pt) - case _ => - true + def constrainResult(mt: Type, pt: Type)(implicit ctx: Context): Boolean = { + val savedConstraint = ctx.typerState.constraint + val res = pt match { + case pt: FunProto => + mt match { + case mt: MethodType => constrainResult(resultTypeApprox(mt), pt.resultType) + case _ => true + } + case _: ValueTypeOrProto if !disregardProto(pt) => + isCompatible(normalize(mt, pt), pt) + case pt: WildcardType if pt.optBounds.exists => + isCompatible(normalize(mt, pt), pt) + case _ => + true + } + if (!res) ctx.typerState.constraint = savedConstraint + res } } diff --git a/tests/neg/i2672.scala b/tests/neg/i2672.scala new file mode 100644 index 000000000000..f958808202a3 --- /dev/null +++ b/tests/neg/i2672.scala @@ -0,0 +1,16 @@ +class Foo[T] + +trait Prepend { + type Out +} + +object Test { + def foo()(implicit ev: Prepend): Foo[ev.Out] = ??? + + def test: Unit = { + foo(): Foo[Any] // error: found: Prepend => Foo[_] required: Foo[Any] + + } + + implicit val p: Prepend = ??? +} diff --git a/tests/pos/i2672.scala b/tests/pos/i2672.scala new file mode 100644 index 000000000000..16be30932c4b --- /dev/null +++ b/tests/pos/i2672.scala @@ -0,0 +1,15 @@ +class Foo[+T] + +trait Prepend { + type Out +} + +object Test { + def foo()(implicit ev: Prepend): Foo[ev.Out] = ??? + + def test: Unit = { + foo(): Foo[Any] + } + + implicit val p: Prepend = ??? +}