summaryrefslogtreecommitdiff
path: root/compiler
Commit message (Collapse)AuthorAgeFilesLines
* Merge remote-tracking branch 'origin/master' into wip/impredicativityAlejandro Serrano2015-07-2790-1201/+2676
|\ | | | | | | | | | | | | | | | | Conflicts: compiler/typecheck/Inst.hs compiler/typecheck/TcBinds.hs compiler/typecheck/TcExpr.hs compiler/typecheck/TcRnTypes.hs compiler/types/Unify.hs
| * Comment tweaks onlyReid Barton2015-07-251-2/+2
| |
| * renamer: fix module-level deprecation messageSergei Trofimovich2015-07-251-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Noticed today that deprecation warnings are slightly broken in -HEAD: mtl-2.2.1/Control/Monad/Error/Class.hs:46:1: warning: Module ‘Control.Monad.Trans.Error’ is deprecated: ([", U, s, e, , C, o, n, t, r, o, l, ., M, o, n, a, d, ., T, r, a, n, s, ., E, x, c, e, p, t, , i, n, s, t, e, a, d, "], Use Control.Monad.Trans.Except instead) Commit e6191d1cc37e98785af8b309100ea840084fa3ba slightly changed WarningTxt declaration: -data WarningTxt = WarningTxt (Located SourceText) [Located FastString] - | DeprecatedTxt (Located SourceText) [Located FastString] +data WarningTxt = WarningTxt (Located SourceText) + [Located (SourceText,FastString)] + | DeprecatedTxt (Located SourceText) + [Located (SourceText,FastString)] But 'moduleWarn' function was not updated to do the stripping. Signed-off-by: Sergei Trofimovich <siarheit@google.com> Reviewers: austin, bgamari, hvr, goldfire, rwbarton, alanz Reviewed By: rwbarton, alanz Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1096 GHC Trac Issues: #10313
| * Improve instanceCantMatchSimon Peyton Jones2015-07-241-2/+6
| | | | | | | | | | | | | | | | | | | | When staring at instanceCantMatch I realised that it was returning False (safe but inefficient) when it could validly return True, on arguments like [Nothing, Just Int] [Just Bool, Just Bool] This patch makes it a bit cleverer.
| * Refactoring around FunDepsSimon Peyton Jones2015-07-243-86/+100
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This refactoring was triggered by Trac #10675. We were using 'improveClsFD' (previously called 'checkClsFD') for both * Improvement: improving a constraint against top-level instances * Consistency: checking when two top-level instances are consistent Using the same code for both seemed attractive at the time, but it's just too complicated. So I've split it: * Improvement: improveClsFD * Consistency: checkFunDeps Much clearer now!
| * Comments about stricteness of catch#Simon Peyton Jones2015-07-241-15/+28
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | In "Improve strictness analysis for exceptions" commit 7c0fff41789669450b02dc1db7f5d7babba5dee6 Author: Simon Peyton Jones <simonpj@microsoft.com> Date: Tue Jul 21 12:28:42 2015 +0100 I made catch# strict in its first argument. But today I found a very old comment suggesting the opposite. I disagree with the old comment, but I've elaborated the Note, which I reproduce here: {- Note [Strictness for mask/unmask/catch] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Consider this example, which comes from GHC.IO.Handle.Internals: wantReadableHandle3 f ma b st = case ... of DEFAULT -> case ma of MVar a -> ... 0# -> maskAsynchExceptions# (\st -> case ma of MVar a -> ...) The outer case just decides whether to mask exceptions, but we don't want thereby to hide the strictness in 'ma'! Hence the use of strictApply1Dmd. For catch, we know that the first branch will be evaluated, but not necessarily the second. Hence strictApply1Dmd and lazyApply1Dmd Howver, consider catch# (\st -> case x of ...) (..handler..) st We'll see that the entire thing is strict in 'x', so 'x' may be evaluated before the catch#. So fi evaluting 'x' causes a divide-by-zero exception, it won't be caught. This seems acceptable: - x might be evaluated somewhere else outside the catch# anyway - It's an imprecise eception anyway. Synchronous exceptions (in the IO monad) will never move in this way. There was originally a comment "Catch is actually strict in its first argument but we don't want to tell the strictness analyser about that, so that exceptions stay inside it." but tracing it back through the commit logs did not give any rationale. And making catch# lazy has performance costs for everyone.
| * Comments onlySimon Peyton Jones2015-07-241-4/+2
| |
| * Library names, with Cabal submodule updateEdward Z. Yang2015-07-235-4/+349
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | A library name is a package name, package version, and hash of the version names of all textual dependencies (i.e. packages which were included.) A library name is a coarse approximation of installed package IDs, which are suitable for inclusion in package keys (you don't want to put an IPID in a package key, since it means the key will change any time the source changes.) - We define ShPackageKey, which is the semantic object which is hashed into a PackageKey. You can use 'newPackageKey' to hash a ShPackageKey to a PackageKey - Given a PackageKey, we can lookup its ShPackageKey with 'lookupPackageKey'. The way we can do this is by consulting the 'pkgKeyCache', which records a reverse mapping from every hash to the ShPackageKey. This means that if you load in PackageKeys from external sources (e.g. interface files), you also need to load in a mapping of PackageKeys to their ShPackageKeys so we can populate the cache. - We define a 'LibraryName' which encapsulates the full depenency resolution that Cabal may have selected; this is opaque to GHC but can be used to distinguish different versions of a package. - Definite packages don't have an interesting PackageKey, so we rely on Cabal to pass them to us. - We can pretty-print package keys while displaying the instantiation, but it's not wired up to anything (e.g. the Outputable instance of PackageKey). Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu> Test Plan: validate Reviewers: austin, bgamari Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1056 GHC Trac Issues: #10566
| * Add a few comments from SPJ on fixity declarationsBen Gamari2015-07-232-2/+20
| |
| * ghci: fixity declarations for infix data constructors (#10018)Thomas Miedema2015-07-232-3/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Declaring a custom fixity for an infix data constructor should work: Prelude> data Infix a b = a :@: b; infixl 4 :@: This is a followup to #2947, which handled fixity declarations in ghci statements (e.g. let add = (+); infixl 6 `add`). Support for declarations (data, type, newtype, class, instance, deriving, and foreign) was added to GHCi in #4929. Reviewers: simonpj, austin, thomie Subscribers: thomie, bgamari Differential Revision: https://phabricator.haskell.org/D1028 GHC Trac Issues: #10018
| * Slight refactoring to the fix for #4012Simon Peyton Jones2015-07-233-20/+22
| | | | | | | | Add CoreSyn.chooseOrphanAnchor, and use it
| * DataCon: Fix redundant importBen Gamari2015-07-231-1/+0
| |
| * Parenthesise TypeOperator in import hintsThomas Winant2015-07-231-4/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When a constructor was mistakenly imported directly instead of as a constructor of a data type, a hint will be shown on how to correctly import it. Just like the constructor, the data type should be surrounded in parentheses if it is an operator (TypeOperator in this case). Instead of: error: In module ‘Data.Type.Equality’: ‘Refl’ is a data constructor of ‘:~:’ To import it use ‘import’ Data.Type.Equality( :~:( Refl ) ) or ‘import’ Data.Type.Equality( :~:(..) ) Print: error: In module ‘Data.Type.Equality’: ‘Refl’ is a data constructor of ‘(:~:)’ To import it use ‘import’ Data.Type.Equality( (:~:)( Refl ) ) or ‘import’ Data.Type.Equality( (:~:)(..) ) Test Plan: pass new test Reviewers: austin, bgamari, simonpj Reviewed By: simonpj Subscribers: simonpj, thomie Differential Revision: https://phabricator.haskell.org/D1093 GHC Trac Issues: #10668
| * Accept next-docstrings on GADT constructors.Ben Gamari2015-07-232-7/+15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Accept next docstrings (`-- | Docstring`) on GADT constructors. I have confirmed that this adds no shift/reduce conflicts. Test Plan: haddockA034 Reviewers: austin, simonpj, simonmar Reviewed By: simonmar Subscribers: Fuuzetsu, simonmar, thomie, mpickering, edsko Differential Revision: https://phabricator.haskell.org/D1086
| * Generate .dyn_o files for .hsig files with -dynamic-tooMichael Smith2015-07-231-1/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | With -dynamic-too, .dyn_o files were not being generated for .hsig files. Normally, this is handled in the pipeline; however, the branch for .hsig files called compileEmptyStub directly instead of going through runPipeline. When compiling a Cabal package that included .hsig files, this triggered a linker error later on, as it expected a .dyn_o file to have been generated for each .hsig. The fix is to use runPipeline for .hsig files, just as with .hs files. Alternately, one could duplicate the logic for handling -dynamic-too in the .hsig branch, but simply calling runPipeline ends up being much cleaner. Test Plan: validate Reviewers: austin, ezyang, bgamari, thomie Reviewed By: ezyang, thomie Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1084 GHC Trac Issues: #10660
| * Lexer: support consecutive references to Haddock chunks (#10398)Thomas Miedema2015-07-231-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | Reviewers: austin, bgamari, Fuuzetsu Reviewed By: bgamari Subscribers: thomie, bgamari Differential Revision: https://phabricator.haskell.org/D1025 GHC Trac Issues: #10398
| * Comments onlySimon Peyton Jones2015-07-231-1/+7
| |
| * Fix Trac #10670Simon Peyton Jones2015-07-232-19/+30
| | | | | | | | | | | | In dataConCannotMatch we were using a GADT data con without properly instantiating the existential type variables. The fix is easy, and the code is tighter.
| * Use lookupIfaceTop for loading IfaceDecls.Edward Z. Yang2015-07-223-9/+10
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Summary: It's shorter! And then when Backpack overrides lookupIfaceTop everyone will see the right information. Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu> Test Plan: validate Reviewers: simonpj, austin, bgamari Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1090
| * Some utility functions for testing IfaceType equality.Edward Z. Yang2015-07-222-2/+140
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Summary: These are going to be used by Backpack, but someone else might find them useful. They do the "obvious thing". Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu> Test Plan: validate Reviewers: goldfire, bgamari, austin Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1089
| * Export alwaysQualifyPackages and neverQualifyPackages.Edward Z. Yang2015-07-221-0/+1
| | | | | | | | Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
| * Give more informative panic for checkFamInstConsistency.Edward Z. Yang2015-07-221-1/+3
| | | | | | | | Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
| * Add ExceptionMonad instance for IOEnv.Edward Z. Yang2015-07-221-0/+10
| | | | | | | | Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
| * Switch from recording IsBootInterface to recording full HscSource.Edward Z. Yang2015-07-227-20/+38
| | | | | | | | | | | | Note: ModIface format change is BC, no need to recompile. Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
| * Eliminate zero_static_objects_list()Simon Marlow2015-07-221-2/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Summary: In a workload with a large amount of code, zero_static_objects_list() takes a significant amount of time, and furthermore it is in the single-threaded part of the GC. This patch uses a slightly fiddly scheme for marking objects on the static object lists, using a flag in the low 2 bits that flips between two states to indicate whether an object has been visited during this GC or not. We also have to take into account objects that have not been visited yet, which might appear at any time due to runtime linking. Test Plan: validate Reviewers: austin, bgamari, ezyang, rwbarton Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1076
| * Add utility function isHoleName.Edward Z. Yang2015-07-211-0/+4
| | | | | | | | Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
| * Make seq-of-cast rule generate a caseSimon Peyton Jones2015-07-212-17/+22
| | | | | | | | | | Previously it generated another call to seq, which triggered a lint failure (Trac #10659)
| * Do occurrence analysis on result of BuiltInRuleSimon Peyton Jones2015-07-211-2/+3
| | | | | | | | | | | | | | | | Previously we did occurrence analysis on the result of a non-built-in RULE, but not of a built-in one. It makes a difference if the rule returns something with binders (which admittedly it usually does not). I'm about to introduce just such a rule for 'seq'.
| * Comments onlySimon Peyton Jones2015-07-211-2/+3
| |
| * Avoid out-of-scope top-level IdsSimon Peyton Jones2015-07-211-16/+15
| | | | | | | | | | | | Pass the top-level SpecEnv to specImports/specImport, so that top-level Ids are in scope. Otherwise we get annoying (but correct) WARNINGS.
| * Comments and white space onlySimon Peyton Jones2015-07-211-3/+5
| |
| * Implement -dsuppress-unfoldingsSimon Peyton Jones2015-07-212-18/+17
| | | | | | | | | | | | | | This extra "suppress" flag helps when there are a lot of Ids with big unfoldings that clutter up the dump Also slightly refactor printing of coercions in Core
| * Add NOINLINE for hs-boot functionsSimon Peyton Jones2015-07-215-80/+154
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This fixes Trac #10083. The key change is in TcBinds.tcValBinds, where we construct the prag_fn. With this patch we add a NOINLINE pragma for any functions that were exported by the hs-boot file for this module. See Note [Inlining and hs-boot files], and #10083, for details. The commit touches several other files becuase I also changed the representation of the "pragma function" from a function TcPragFun to an environment, TcPragEnv. This makes it easer to extend during construction.
| * Refactor self-boot infoSimon Peyton Jones2015-07-218-153/+184
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This patch is a simple refactoring that prepares for a later one, related to Trac #10083. * Add a field tcg_self_boot :: SelfBootInfo to TcGblEnv, where SelfBootInfo is a new data type, describing the hi-boot file, if any, for the module being compiled. * Make tcHiBootIface return SelfBootInfo, a new data type * Make other functions get SelfBootInfo from the monad. * Remove tcg_mod_name from TcGblEnv; it was barely used and simpler to pass around explicitly.
| * Comments and white space onlySimon Peyton Jones2015-07-211-18/+18
| |
| * Improve strictness analysis for exceptionsSimon Peyton Jones2015-07-213-37/+85
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Two things here: * For exceptions-catching primops like catch#, we know that the main argument function will be called, so we can use strictApply1Dmd, rather than lazy Changes in primops.txt.pp * When a 'case' scrutinises a I/O-performing primop, the Note [IO hack in the demand analyser] was throwing away all strictness from the code that followed. I found that this was causing quite a bit of unnecessary reboxing in the (heavily used) function GHC.IO.Handle.Internals.wantReadableHandle So this patch prevents the hack applying when the case scrutinises a primop. See the revised Note [IO hack in the demand analyser] Thse two things buy us quite a lot in programs that do a lot of IO. Program Size Allocs Runtime Elapsed TotalMem -------------------------------------------------------------------------------- hpg -0.4% -2.9% -0.9% -1.0% +0.0% reverse-complem -0.4% -10.9% +10.7% +10.9% +0.0% simple -0.3% -0.0% +26.2% +26.2% +3.7% sphere -0.3% -6.3% 0.09 0.09 +0.0% -------------------------------------------------------------------------------- Min -0.7% -10.9% -4.6% -4.7% -1.7% Max -0.2% +0.0% +26.2% +26.2% +6.5% Geometric Mean -0.4% -0.3% +2.1% +2.1% +0.1% I think the increase in runtime for 'simple' is measurement error.
| * Refactor newSCWorkFromFlavouredSimon Peyton Jones2015-07-211-18/+22
| | | | | | | | No change in behaviour is intended here
| * Comments only (superclasses and improvement)Simon Peyton Jones2015-07-212-52/+22
| |
| * Use varToCoreExpr in mkWWcpr_helpSimon Peyton Jones2015-07-211-1/+3
| | | | | | | | | | Lacking this cuased Trac #10658. The fix is easy; it was a simple omission.
| * Delete __GLASGOW_HASKELL__ ifdefs for stage0 < 7.8Thomas Miedema2015-07-214-68/+1
| | | | | | | | | | | | | | | | | | | | Reviewers: austin, goldfire, bgamari Reviewed By: bgamari Subscribers: bgamari, thomie Differential Revision: https://phabricator.haskell.org/D904
| * primops: Fix spelling mistakeBen Gamari2015-07-211-1/+1
| |
| * Revert "Revert "Support for multiple signature files in scope.""Edward Z. Yang2015-07-2011-136/+350
| | | | | | | | | | | | | | This reverts commit bac927b9770ff769128b66d13a3e72bf5a9bc514. As it turns out, we need these commits for separate compilation and accurate dependency tracking. So back in they go!
| * Revert "Revert "Change loadSrcInterface to return a list of ModIface""Edward Z. Yang2015-07-204-38/+96
| | | | | | | | This reverts commit c60704fc405149407c155e297433f1cc299ae58a.
| * Fix primops documentation syntaxBen Gamari2015-07-201-8/+8
| |
| * Do not treat prim and javascript imports as C imports in TH and QQLuite Stegeman2015-07-202-7/+18
| | | | | | | | | | | | | | | | | | | | | | | | Reviewers: austin, hvr, goldfire, bgamari Reviewed By: bgamari Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1070 GHC Trac Issues: #10638
| * primops: Add haddocks to BCO primopsBen Gamari2015-07-201-1/+11
| | | | | | | | | | | | | | | | | | | | | | | | Test Plan: none Reviewers: simonmar, austin, hvr Subscribers: hvr, thomie Differential Revision: https://phabricator.haskell.org/D1082 GHC Trac Issues: #10640
| * Support wild cards in TH splicesThomas Winant2015-07-206-50/+161
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | - Declaration splices: partial type signatures are fully supported in TH declaration splices. For example, the wild cards in the example below will unify with `Eq a` and `a -> a -> Bool`, as expected: ``` [d| foo :: _ => _ foo x y = x == y |] ``` - Expression splices: anonymous and named wild cards are supported in expression signatures, but extra-constraints wild cards aren't. Just as is the case for regular expression signatures. ``` [e | Just True :: _a _ |] ``` - Typed expression splices: the same wildcards as in (untyped) expression splices are supported. - Pattern splices: TH doesn't support type signatures in pattern splices, consequently, partial type signatures aren't supported either. - Type splices: partial type signatures are only partially supported in type splices, specifically: only anonymous wild cards are allowed. So `[t| _ |]`, `[t| _ -> Maybe _ |]` will work, but `[t| _ => _ |]` or `[| _a |]` won't (without `-XNamedWildCards`, the latter will work as the named wild card is treated as a type variable). Normally, named wild cards are collected before renaming a (partial) type signature. However, TH type splices are run during renaming, i.e. after the initial traversal, leading to out of scope errors for named wild cards. We can't just extend the initial traversal to collect the named wild cards in TH type splices, as we'd need to expand them, which is supposed to happen only once, during renaming. Similarly, the extra-constraints wild card is handled right before renaming too, and is therefore also not supported in a TH type splice. Another reason not to support extra-constraints wild cards in TH type splices is that a single signature can contain many TH type splices, whereas it mustn't contain more than one extra-constraints wild card. Enforcing would this be hard the way things are currently organised. Anonymous wild cards pose no problem, because they start without names and are given names during renaming. These names are collected right after renaming. The names generated for anonymous wild cards in TH type splices will thus be collected as well. With a more invasive refactoring of the renaming, partial type signatures could be fully supported in TH type splices. As only anonymous wild cards have been requested so far, these small changes satisfying this request will do for now. Also don't forget that a TH declaration splices support all kinds of wild cards. - Extra-constraints wild cards were silently ignored in expression and pattern signatures, appropriate error messages are now generated. Test Plan: run new tests Reviewers: austin, goldfire, adamgundry, bgamari Reviewed By: goldfire, adamgundry, bgamari Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1048 GHC Trac Issues: #10094, #10548
| * LlvmCodeGen: add support for MO_U_Mul2 CallishMachOpMichal Terepeta2015-07-202-1/+36
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This adds support MO_U_Mul2 to the LLVM backend by simply using 'mul' instruction but operating at twice the bit width (e.g., for 64 bit words we will generate mul that operates on 128 bits and then extract the two 64 bit values for the result of the CallishMachOp). Test Plan: validate Reviewers: rwbarton, austin, bgamari Reviewed By: bgamari Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1068 GHC Trac Issues: #9430
| * Update assert to fix retc001 and retc002 (#9243)Thomas Miedema2015-07-181-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | Since 2223e196b2dc5340d70e58be011c279d381b4319, maybe_old_linkable can be Nothing even with an up-to-date interface file. This happens when compiling with --make -fno-code -fwrite-interface. See also Note [Recompilation checking when typechecking only] in GhcMake.hs. This fixes retc001 and retc002 when ghc_debugged. Differential Revision: https://phabricator.haskell.org/D1077
| * Reduce non-determinism in ABI hashes with RULES and instance declsBartosz Nitka2015-07-172-6/+19
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Summary: Before this change the `RULES` would be attached to one for the names from the module that appear on the left hand side. The choice depended on the `uniq` that was generated, which are known to be non-deterministic (a separate, bigger problem). Now we use `OccName`s which should be stable. Analogously for instance declarations, but they are attached to one of the types involved. Test Plan: contbuild it made `Data.Text.Internal.Fusion.Common` interface stable, previously stream fusion rule would be attached either to `streamList` or `unstreamList` depending on if the module was compiled after `cabal clean` or after `find | grep '\.o$' | xargs rm`. Reviewers: simonpj, austin, bgamari, simonmar Subscribers: puffnfresh, thomie Differential Revision: https://phabricator.haskell.org/D1073 GHC Trac Issues: #4012