From 291492f19b2b70ce379eb3539a651e1198af5aec Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 19 Jul 2017 21:21:21 +0200 Subject: [PATCH 1/3] Make sure constrainResult does not change context when false constrainResult should behave like isSubType in this respect. This fixes #2672. The assertion in Applications.scala is no longer needed because it is now obviously true by design. --- .../dotty/tools/dotc/typer/Applications.scala | 4 +-- .../dotty/tools/dotc/typer/ProtoTypes.scala | 31 ++++++++++--------- tests/neg/i2672.scala | 16 ++++++++++ tests/pos/i2672.scala | 15 +++++++++ 4 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 tests/neg/i2672.scala create mode 100644 tests/pos/i2672.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index f8189fb8f9ee..bb607a916585 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -217,11 +217,11 @@ trait Applications extends Compatibility { self: Typer with Dynamic => // apply the result type constraint, unless method type is dependent val resultApprox = resultTypeApprox(methType) val savedConstraint = ctx.typerState.constraint - if (!constrainResult(resultApprox, resultType)) + 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 = ??? +} From 1d80e66f958c78e32490d5e6301c5db46e25f457 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 19 Jul 2017 21:55:51 +0200 Subject: [PATCH 2/3] Fix typo --- compiler/src/dotty/tools/dotc/typer/Applications.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index bb607a916585..b0fac54d0c2d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -217,7 +217,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => // apply the result type constraint, unless method type is dependent val resultApprox = resultTypeApprox(methType) val savedConstraint = ctx.typerState.constraint - if (!constrainResult(resultApprox, resultType) + if (!constrainResult(resultApprox, resultType)) if (ctx.typerState.isCommittable) // defer the problem until after the application; // it might be healed by an implicit conversion From ba801d5ca48e1bfc4f284fd071b7571a32283928 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 19 Jul 2017 22:08:25 +0200 Subject: [PATCH 3/3] Remove unused definition --- compiler/src/dotty/tools/dotc/typer/Applications.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index b0fac54d0c2d..46640b02c021 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -216,7 +216,6 @@ 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;