diff options
author | Ryan Scott <ryan.gl.scott@gmail.com> | 2020-03-24 18:44:08 -0400 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-03-29 17:33:20 -0400 |
commit | a0d8e92e9c9b67426aa139d6bc46363d8940f992 (patch) | |
tree | 9fdca21dbaae8f20633d3673a3750be866b851f5 /testsuite | |
parent | 64bf7f51064dad9c63728ac8bccdb9cf00bdb420 (diff) | |
download | haskell-a0d8e92e9c9b67426aa139d6bc46363d8940f992.tar.gz |
Run checkNewDataCon before constraint-solving newtype constructors
Within `checkValidDataCon`, we used to run `checkValidType` on the
argument types of a newtype constructor before running
`checkNewDataCon`, which ensures that the user does not attempt
non-sensical things such as newtypes with multiple arguments or
constraints. This works out in most situations, but this falls over
on a corner case revealed in #17955:
```hs
newtype T = Coercible () T => T ()
```
`checkValidType`, among other things, peforms an ambiguity check on
the context of a data constructor, and that it turn invokes the
constraint solver. It turns out that there is a special case in the
constraint solver for representational equalities (read: `Coercible`
constraints) that causes newtypes to be unwrapped (see
`Note [Unwrap newtypes first]` in `TcCanonical`). This special case
does not know how to cope with an ill formed newtype like `T`, so
it ends up panicking.
The solution is surprisingly simple: just invoke `checkNewDataCon`
before `checkValidType` to ensure that the illicit newtype
constructor context is detected before the constraint solver can
run amok with it.
Fixes #17955.
Diffstat (limited to 'testsuite')
-rw-r--r-- | testsuite/tests/typecheck/should_fail/T17955.hs | 6 | ||||
-rw-r--r-- | testsuite/tests/typecheck/should_fail/T17955.stderr | 6 | ||||
-rw-r--r-- | testsuite/tests/typecheck/should_fail/all.T | 1 |
3 files changed, 13 insertions, 0 deletions
diff --git a/testsuite/tests/typecheck/should_fail/T17955.hs b/testsuite/tests/typecheck/should_fail/T17955.hs new file mode 100644 index 0000000000..1bcb9a6d90 --- /dev/null +++ b/testsuite/tests/typecheck/should_fail/T17955.hs @@ -0,0 +1,6 @@ +{-# LANGUAGE FlexibleContexts #-} +module T17955 where + +import Data.Coerce + +newtype T = Coercible () T => T () diff --git a/testsuite/tests/typecheck/should_fail/T17955.stderr b/testsuite/tests/typecheck/should_fail/T17955.stderr new file mode 100644 index 0000000000..0762facf45 --- /dev/null +++ b/testsuite/tests/typecheck/should_fail/T17955.stderr @@ -0,0 +1,6 @@ + +T17955.hs:6:13: error: + • A newtype constructor cannot have a context in its type + T :: Coercible () T => () -> T + • In the definition of data constructor ‘T’ + In the newtype declaration for ‘T’ diff --git a/testsuite/tests/typecheck/should_fail/all.T b/testsuite/tests/typecheck/should_fail/all.T index 4f8f08ed85..14728794ce 100644 --- a/testsuite/tests/typecheck/should_fail/all.T +++ b/testsuite/tests/typecheck/should_fail/all.T @@ -561,3 +561,4 @@ test('T17566c', normal, compile_fail, ['']) test('T17773', normal, compile_fail, ['']) test('T17021', normal, compile_fail, ['']) test('T17021b', normal, compile_fail, ['']) +test('T17955', normal, compile_fail, ['']) |