2022-02-15 16:12:53 +03:00
|
|
|
module Scope.Negative (allTests) where
|
|
|
|
|
|
|
|
import Base
|
2022-08-03 14:20:40 +03:00
|
|
|
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.Scoping.Error
|
2022-02-15 16:12:53 +03:00
|
|
|
|
|
|
|
type FailMsg = String
|
|
|
|
|
2022-07-05 16:54:01 +03:00
|
|
|
data NegTest a = NegTest
|
2022-04-07 19:10:53 +03:00
|
|
|
{ _name :: String,
|
2022-12-20 15:05:40 +03:00
|
|
|
_relDir :: Path Rel Dir,
|
|
|
|
_file :: Path Rel File,
|
2022-07-05 16:54:01 +03:00
|
|
|
_checkErr :: a -> Maybe FailMsg
|
2022-02-15 16:12:53 +03:00
|
|
|
}
|
|
|
|
|
2022-12-20 15:05:40 +03:00
|
|
|
root :: Path Abs Dir
|
|
|
|
root = relToProject $(mkRelDir "tests/negative")
|
2022-04-07 19:10:53 +03:00
|
|
|
|
Update CI to install Smoke, Github actions, and Makefile fixes (#1735)
This PR adds some maintenance at different levels to the CI config, the
Make file, and formatting.
- Most of the actions used by the CI related to haskell, ormolu, hlint
and pre-commit have been updated because Github requires NodeJS 16. This
change removes all the old warnings related to nodeJs.
In the case of ormolu, the new version makes us format some files that
were not formatted before, similarly with hlint.
- The CI has been updated to use the latest version of the Smoke testing
framework, which introduced installation of the dependencies for Linux
(libicu66) and macOS (icu4c) in the CI. In the case of macOS, the CI
uses a binary for smoke. For Linux, we use stack to build smoke from the
source. The source here is in a fork of [the official Smoke
repo](https://github.com/SamirTalwar/smoke). Such includes some
features/changes that are not yet in the official repo.
- The Makefile runs the ormolu and hlint targets using as a path for the
binaries the environment variables ORMOLU and HLINT. Thus, export those
variables in your environment before running `make check,` `make format`
or `make hlint`. Otherwise, the Makefile will use the binaries provided
by `stack`.
Co-authored-by: Paul Cadman <git@paulcadman.dev>
2023-01-24 13:50:23 +03:00
|
|
|
testDescr :: (Typeable a) => NegTest a -> TestDescr
|
2022-04-05 20:57:21 +03:00
|
|
|
testDescr NegTest {..} =
|
2022-12-20 15:05:40 +03:00
|
|
|
let tRoot = root <//> _relDir
|
|
|
|
file' = tRoot <//> _file
|
2022-04-07 19:10:53 +03:00
|
|
|
in TestDescr
|
|
|
|
{ _testName = _name,
|
|
|
|
_testRoot = tRoot,
|
|
|
|
_testAssertion = Single $ do
|
2023-04-13 12:27:39 +03:00
|
|
|
entryPoint <- defaultEntryPointCwdIO file'
|
2023-06-30 16:01:46 +03:00
|
|
|
res <- runIOEither entryPoint upToInternal
|
2022-07-08 14:59:45 +03:00
|
|
|
case mapLeft fromJuvixError res of
|
2022-04-07 19:10:53 +03:00
|
|
|
Left (Just err) -> whenJust (_checkErr err) assertFailure
|
2022-12-20 15:05:40 +03:00
|
|
|
Left Nothing -> assertFailure "An error ocurred but it was not in the scoper."
|
|
|
|
Right {} -> assertFailure "The scope checker did not find an error."
|
2022-04-07 19:10:53 +03:00
|
|
|
}
|
2022-02-15 16:12:53 +03:00
|
|
|
|
2022-02-18 15:01:42 +03:00
|
|
|
allTests :: TestTree
|
2022-04-05 20:57:21 +03:00
|
|
|
allTests =
|
|
|
|
testGroup
|
|
|
|
"Scope negative tests"
|
2022-07-05 16:54:01 +03:00
|
|
|
( map (mkTest . testDescr) scoperErrorTests
|
|
|
|
)
|
2022-02-16 22:15:14 +03:00
|
|
|
|
2022-02-16 17:18:08 +03:00
|
|
|
wrongError :: Maybe FailMsg
|
2022-02-15 16:12:53 +03:00
|
|
|
wrongError = Just "Incorrect error"
|
|
|
|
|
2022-07-05 16:54:01 +03:00
|
|
|
scoperErrorTests :: [NegTest ScoperError]
|
|
|
|
scoperErrorTests =
|
2022-04-05 20:57:21 +03:00
|
|
|
[ NegTest
|
|
|
|
"Not in scope"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "NotInScope.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
|
|
|
ErrSymNotInScope {} -> Nothing
|
|
|
|
_ -> wrongError,
|
2022-05-18 18:10:10 +03:00
|
|
|
NegTest
|
|
|
|
"Qualified not in scope"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "QualSymNotInScope.juvix")
|
2022-05-18 18:10:10 +03:00
|
|
|
$ \case
|
|
|
|
ErrQualSymNotInScope {} -> Nothing
|
|
|
|
_ -> wrongError,
|
2022-04-05 20:57:21 +03:00
|
|
|
NegTest
|
|
|
|
"Multiple declarations"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "MultipleDeclarations.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
|
|
|
ErrMultipleDeclarations {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Import cycle"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir "ImportCycle")
|
|
|
|
$(mkRelFile "A.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
|
|
|
ErrImportCycle {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Binding group conflict (function clause)"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir "BindGroupConflict")
|
|
|
|
$(mkRelFile "Clause.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
2023-02-22 12:26:54 +03:00
|
|
|
ErrMultipleDeclarations {} -> Nothing
|
2022-04-05 20:57:21 +03:00
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Binding group conflict (lambda clause)"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir "BindGroupConflict")
|
|
|
|
$(mkRelFile "Lambda.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
2023-02-22 12:26:54 +03:00
|
|
|
ErrMultipleDeclarations {} -> Nothing
|
2022-04-05 20:57:21 +03:00
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Infix error (expression)"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "InfixError.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
|
|
|
ErrInfixParser {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Infix error (pattern)"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "InfixErrorP.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
|
|
|
ErrInfixPattern {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Duplicate fixity declaration"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "DuplicateFixity.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
|
|
|
ErrDuplicateFixity {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Multiple export conflict"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "MultipleExportConflict.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
|
|
|
ErrMultipleExport {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Module not in scope"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "ModuleNotInScope.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
|
|
|
ErrModuleNotInScope {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Unused operator syntax definition"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "UnusedOperatorDef.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
|
|
|
ErrUnusedOperatorDef {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Ambiguous symbol"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "AmbiguousSymbol.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
|
|
|
ErrAmbiguousSym {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Lacks function clause"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "LacksFunctionClause.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
|
|
|
ErrLacksFunctionClause {} -> Nothing
|
|
|
|
_ -> wrongError,
|
2023-01-17 11:41:07 +03:00
|
|
|
NegTest
|
|
|
|
"Lacks function clause inside let"
|
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "LetMissingClause.juvix")
|
|
|
|
$ \case
|
|
|
|
ErrLacksFunctionClause {} -> Nothing
|
|
|
|
_ -> wrongError,
|
2022-04-05 20:57:21 +03:00
|
|
|
NegTest
|
|
|
|
"Ambiguous export"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "AmbiguousExport.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
|
|
|
ErrMultipleExport {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Ambiguous nested modules"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "AmbiguousModule.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
|
|
|
ErrAmbiguousModuleSym {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Ambiguous nested constructors"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "AmbiguousConstructor.juvix")
|
2022-04-05 20:57:21 +03:00
|
|
|
$ \case
|
|
|
|
ErrAmbiguousSym {} -> Nothing
|
2022-04-28 18:42:15 +03:00
|
|
|
_ -> wrongError,
|
2022-06-14 09:56:48 +03:00
|
|
|
NegTest
|
|
|
|
"Implicit argument on the left of an application"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "AppLeftImplicit.juvix")
|
2022-06-14 09:56:48 +03:00
|
|
|
$ \case
|
|
|
|
ErrAppLeftImplicit {} -> Nothing
|
|
|
|
_ -> wrongError,
|
2022-07-04 17:40:10 +03:00
|
|
|
NegTest
|
|
|
|
"issue 230"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir "230")
|
|
|
|
$(mkRelFile "Prod.juvix")
|
2022-07-04 17:40:10 +03:00
|
|
|
$ \case
|
|
|
|
ErrQualSymNotInScope {} -> Nothing
|
|
|
|
_ -> wrongError,
|
2022-07-20 17:24:03 +03:00
|
|
|
NegTest
|
|
|
|
"Double braces in pattern"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "NestedPatternBraces.juvix")
|
2022-07-20 17:24:03 +03:00
|
|
|
$ \case
|
|
|
|
ErrDoubleBracesPattern {} -> Nothing
|
|
|
|
_ -> wrongError,
|
2022-11-03 12:02:22 +03:00
|
|
|
NegTest
|
|
|
|
"As-Pattern aliasing variable"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "AsPatternAlias.juvix")
|
2022-11-03 12:02:22 +03:00
|
|
|
$ \case
|
|
|
|
ErrAliasBinderPattern {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Nested As-Patterns"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "NestedAsPatterns.juvix")
|
2022-11-03 12:02:22 +03:00
|
|
|
$ \case
|
|
|
|
ErrDoubleBinderPattern {} -> Nothing
|
|
|
|
_ -> wrongError,
|
2022-07-20 17:24:03 +03:00
|
|
|
NegTest
|
|
|
|
"Pattern matching an implicit argument on the left of an application"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "ImplicitPatternLeftApplication.juvix")
|
2022-07-20 17:24:03 +03:00
|
|
|
$ \case
|
|
|
|
ErrImplicitPatternLeftApplication {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Constructor expected on the left of a pattern application"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "ConstructorExpectedLeftApplication.juvix")
|
2022-07-20 17:24:03 +03:00
|
|
|
$ \case
|
|
|
|
ErrConstructorExpectedLeftApplication {} -> Nothing
|
|
|
|
_ -> wrongError,
|
2022-07-15 11:58:49 +03:00
|
|
|
NegTest
|
|
|
|
"A type parameter name occurs twice when declaring an inductive type"
|
2022-12-20 15:05:40 +03:00
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "DuplicateInductiveParameterName.juvix")
|
2022-07-15 11:58:49 +03:00
|
|
|
$ \case
|
2023-02-22 12:26:54 +03:00
|
|
|
ErrMultipleDeclarations {} -> Nothing
|
2023-01-31 11:46:53 +03:00
|
|
|
_ -> wrongError,
|
2023-02-22 12:26:54 +03:00
|
|
|
NegTest
|
|
|
|
"A function lacks a type signature"
|
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "LacksTypeSig.juvix")
|
|
|
|
$ \case
|
|
|
|
ErrLacksTypeSig {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"A function inside a let lacks a type signature that is at the top level"
|
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "LacksTypeSig2.juvix")
|
|
|
|
$ \case
|
|
|
|
ErrLacksTypeSig {} -> Nothing
|
2023-05-22 12:41:13 +03:00
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Using symbol that is not exported"
|
|
|
|
$(mkRelDir "UsingHiding")
|
|
|
|
$(mkRelFile "Main.juvix")
|
|
|
|
$ \case
|
|
|
|
ErrModuleDoesNotExportSymbol {} -> Nothing
|
Iterator syntax (#2126)
* Closes #1992
A function identifier `fun` can be declared as an iterator with
```
syntax iterator fun;
```
For example:
```haskell
syntax iterator for;
for : {A B : Type} -> (A -> B -> A) -> A -> List B -> List A;
for f acc nil := acc;
for f acc (x :: xs) := for (f acc x) xs;
```
Iterator application syntax allows for a finite number of initializers
`acc := a` followed by a finite number of ranges `x in xs`. For example:
```
for (acc := 0) (x in lst) acc + x
```
The number of initializers plus the number of ranges must be non-zero.
An iterator application
```
fun (acc1 := a1; ..; accn := an) (x1 in b1; ..; xk in bk) body
```
gets desugared to
```
fun \{acc1 .. accn x1 .. xk := body} a1 .. an b1 .. bk
```
The `acc1`, ..., `accn`, `x1`, ..., `xk` can be patterns.
The desugaring works on a purely syntactic level. Without further
restrictions, it is not checked if the number of initializers/ranges
matches the type of the identifier. The restrictions on the number of
initializers/ranges can be specified in iterator declaration:
```
syntax iterator fun {init: n, range: k};
syntax iterator for {init: 1, range: 1};
syntax iterator map {init: 0, range: 1};
```
The attributes (`init`, `range`) in between braces are parsed as YAML to
avoid inventing and parsing a new attribute language. Both attributes
are optional.
2023-05-30 16:30:11 +03:00
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Wrong number of interator initializers"
|
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "Iterators1.juvix")
|
|
|
|
$ \case
|
|
|
|
ErrIteratorInitializer {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Wrong number of interator ranges"
|
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "Iterators2.juvix")
|
|
|
|
$ \case
|
|
|
|
ErrIteratorRange {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Undeclared iterator"
|
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "Iterators3.juvix")
|
|
|
|
$ \case
|
|
|
|
ErrIteratorUndefined {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Duplicate iterator declaration"
|
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "Iterators4.juvix")
|
|
|
|
$ \case
|
|
|
|
ErrDuplicateIterator {} -> Nothing
|
|
|
|
_ -> wrongError,
|
|
|
|
NegTest
|
|
|
|
"Unused iterator declaration"
|
|
|
|
$(mkRelDir ".")
|
|
|
|
$(mkRelFile "Iterators5.juvix")
|
|
|
|
$ \case
|
|
|
|
ErrUnusedIteratorDef {} -> Nothing
|
2022-04-05 20:57:21 +03:00
|
|
|
_ -> wrongError
|
2022-02-16 22:15:14 +03:00
|
|
|
]
|