packages feed

hydra-kernel-0.16.0: src/main/haskell/Hydra/Checking.hs

-- Note: this is an automatically generated file. Do not edit.
-- | Type checking and type reconstruction (type-of) for the results of Hydra unification and inference

module Hydra.Checking where
import qualified Hydra.Ast as Ast
import qualified Hydra.Coders as Coders
import qualified Hydra.Constants as Constants
import qualified Hydra.Core as Core
import qualified Hydra.Dependencies as Dependencies
import qualified Hydra.Error.Checking as Checking
import qualified Hydra.Error.Core as ErrorCore
import qualified Hydra.Error.Packaging as ErrorPackaging
import qualified Hydra.Errors as Errors
import qualified Hydra.Extract.Core as ExtractCore
import qualified Hydra.Formatting as Formatting
import qualified Hydra.Graph as Graph
import qualified Hydra.Json.Model as Model
import qualified Hydra.Lexical as Lexical
import qualified Hydra.Haskell.Lib.Eithers as Eithers
import qualified Hydra.Haskell.Lib.Equality as Equality
import qualified Hydra.Haskell.Lib.Lists as Lists
import qualified Hydra.Haskell.Lib.Literals as Literals
import qualified Hydra.Haskell.Lib.Logic as Logic
import qualified Hydra.Haskell.Lib.Maps as Maps
import qualified Hydra.Haskell.Lib.Optionals as Optionals
import qualified Hydra.Haskell.Lib.Pairs as Pairs
import qualified Hydra.Haskell.Lib.Sets as Sets
import qualified Hydra.Haskell.Lib.Strings as Strings
import qualified Hydra.Names as Names
import qualified Hydra.Packaging as Packaging
import qualified Hydra.Parsing as Parsing
import qualified Hydra.Paths as Paths
import qualified Hydra.Query as Query
import qualified Hydra.Reflect as Reflect
import qualified Hydra.Relational as Relational
import qualified Hydra.Resolution as Resolution
import qualified Hydra.Rewriting as Rewriting
import qualified Hydra.Scoping as Scoping
import qualified Hydra.Show.Core as ShowCore
import qualified Hydra.Show.Errors as ShowErrors
import qualified Hydra.Show.Variants as ShowVariants
import qualified Hydra.Strip as Strip
import qualified Hydra.Substitution as Substitution
import qualified Hydra.Tabular as Tabular
import qualified Hydra.Testing as Testing
import qualified Hydra.Topology as Topology
import qualified Hydra.Typed as Typed
import qualified Hydra.Typing as Typing
import qualified Hydra.Util as Util
import qualified Hydra.Validation as Validation
import qualified Hydra.Variables as Variables
import qualified Hydra.Variants as Variants
import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, map, pure, sum)
import qualified Data.Scientific as Sci
import qualified Data.Map as M
import qualified Data.Set as S
-- | True if every element of the list is equal to every other element (vacuously true for the empty list)
allEqual :: Eq t0 => ([t0] -> Bool)
allEqual els =
    Optionals.cases (Lists.uncons els) True (\uc ->
      let h = Pairs.first uc
          t = Pairs.second uc
      in (Lists.foldl (\b -> \x -> Logic.and b (Equality.equal x h)) True t))
-- | Apply type arguments to a type, substituting forall-bound variables
applyTypeArgumentsToType :: t0 -> Graph.Graph -> [Core.Type] -> Core.Type -> Either Errors.Error Core.Type
applyTypeArgumentsToType cx tx typeArgs t =
    Optionals.cases (Lists.uncons typeArgs) (Right t) (\uc ->
      let ah = Pairs.first uc
          at = Pairs.second uc
      in case t of
        Core.TypeForall v0 ->
          let v = Core.forallTypeParameter v0
              tbody = Core.forallTypeBody v0
          in (applyTypeArgumentsToType cx tx at (Substitution.substInType (Typing.TypeSubst (Maps.singleton v ah)) tbody))
        _ -> Left (Errors.ErrorExtraction (Errors.ExtractionErrorUnexpectedShape (Errors.UnexpectedShapeError {
          Errors.unexpectedShapeErrorExpected = "forall type",
          Errors.unexpectedShapeErrorActual = (Strings.cat [
            ShowCore.type_ t,
            ". Trying to apply ",
            (Literals.showInt32 (Lists.length typeArgs)),
            " type args: ",
            (Formatting.showList ShowCore.type_ typeArgs),
            ". Context has vars: {",
            (Strings.intercalate ", " (Lists.map Core.unName (Maps.keys (Graph.graphBoundTypes tx)))),
            "}"])}))))
-- | Check that a term has no unbound type variables (Either version)
checkForUnboundTypeVariables :: t0 -> Graph.Graph -> Core.Term -> Either Errors.Error ()
checkForUnboundTypeVariables cx tx term0 =

      let svars = Sets.fromList (Maps.keys (Graph.graphSchemaTypes tx))
          checkRecursive =
                  \vars -> \trace -> \lbinding -> \term ->
                    let recurse = checkRecursive vars trace lbinding
                        dflt = Eithers.bind (Eithers.mapList recurse (Rewriting.subterms term)) (\_ -> Right ())
                        check =
                                \typ ->
                                  let freevars = Variables.freeVariablesInType typ
                                      badvars = Sets.difference (Sets.difference freevars vars) svars
                                  in (Logic.ifElse (Sets.null badvars) (Right ()) (Left (Errors.ErrorChecking (Checking.CheckingErrorUnboundTypeVariables (Checking.UnboundTypeVariablesError {
                                    Checking.unboundTypeVariablesErrorVariables = badvars,
                                    Checking.unboundTypeVariablesErrorType = typ})))))
                        checkOptional = \m -> Eithers.bind (Eithers.mapOptional check m) (\_ -> Right ())
                    in case term of
                      Core.TermLambda v0 -> Eithers.bind (checkOptional (Core.lambdaDomain v0)) (\_ -> recurse (Core.lambdaBody v0))
                      Core.TermLet v0 ->
                        let forBinding =
                                \b ->
                                  let bterm = Core.bindingTerm b
                                      newVars =
                                              Optionals.cases (Core.bindingTypeScheme b) vars (\ts -> Sets.union vars (Sets.fromList (Core.typeSchemeVariables ts)))
                                      newTrace = Lists.cons (Core.unName (Core.bindingName b)) trace
                                  in (checkRecursive newVars newTrace (Just b) bterm)
                        in (Eithers.bind (Eithers.mapList forBinding (Core.letBindings v0)) (\_ -> recurse (Core.letBody v0)))
                      Core.TermTypeApplication v0 -> Eithers.bind (check (Core.typeApplicationTermType v0)) (\_ -> recurse (Core.typeApplicationTermBody v0))
                      Core.TermTypeLambda v0 -> Eithers.bind (check (Core.TypeVariable (Core.typeLambdaParameter v0))) (\_ -> recurse (Core.typeLambdaBody v0))
                      _ -> dflt
      in (checkRecursive Sets.empty [
        "top level"] Nothing term0)
-- | Check that a nominal type is applied to the correct number of type arguments (Either version)
checkNominalApplication :: Typing.InferenceContext -> Graph.Graph -> Core.Name -> [Core.Type] -> Either Errors.Error ((), Typing.InferenceContext)
checkNominalApplication cx tx tname typeArgs =
    Eithers.bind (Resolution.requireSchemaType cx (Graph.graphSchemaTypes tx) tname) (\result ->
      let schemaType = Pairs.first result
          cx2 = Pairs.second result
          vars = Core.typeSchemeVariables schemaType
          varslen = Lists.length vars
          argslen = Lists.length typeArgs
      in (Logic.ifElse (Equality.equal varslen argslen) (Right ((), cx2)) (Left (Errors.ErrorChecking (Checking.CheckingErrorTypeArityMismatch (Checking.TypeArityMismatchError {
        Checking.typeArityMismatchErrorType = (Core.TypeVariable tname),
        Checking.typeArityMismatchErrorExpectedArity = varslen,
        Checking.typeArityMismatchErrorActualArity = argslen,
        Checking.typeArityMismatchErrorTypeArguments = typeArgs}))))))
-- | Ensure all types in a list are equal and return the common type
checkSameType :: t0 -> Graph.Graph -> String -> [Core.Type] -> Either Errors.Error Core.Type
checkSameType cx tx desc types =

      let unequalErr =
              Left (Errors.ErrorChecking (Checking.CheckingErrorUnequalTypes (Checking.UnequalTypesError {
                Checking.unequalTypesErrorTypes = types,
                Checking.unequalTypesErrorDescription = desc})))
      in (Logic.ifElse (typesAllEffectivelyEqual tx types) (Optionals.cases (Lists.maybeHead types) unequalErr (\t -> Right t)) unequalErr)
-- | Check that a term has the expected type
checkType :: Typing.InferenceContext -> Graph.Graph -> Core.Term -> Core.Type -> Either Errors.Error ()
checkType cx tx term typ =

      let vars = Graph.graphTypeVariables tx
      in (Logic.ifElse Constants.debugInference (Eithers.bind (Eithers.map (\_p -> Pairs.first _p) (typeOf cx tx [] term)) (\t0 -> Logic.ifElse (typesEffectivelyEqual tx t0 typ) (Right ()) (Left (Errors.ErrorChecking (Checking.CheckingErrorTypeMismatch (Checking.TypeMismatchError {
        Checking.typeMismatchErrorExpectedType = typ,
        Checking.typeMismatchErrorActualType = t0})))))) (Right ()))
-- | Sanity-check a type substitution arising from unification. Specifically, check that schema types have not been inappropriately unified with type variables inferred from terms.
checkTypeSubst :: t0 -> Graph.Graph -> Typing.TypeSubst -> Either Errors.Error Typing.TypeSubst
checkTypeSubst cx tx subst =

      let s = Typing.unTypeSubst subst
          vars = Sets.fromList (Maps.keys s)
          suspectVars = Sets.intersection vars (Sets.fromList (Maps.keys (Graph.graphSchemaTypes tx)))
          isNominal =
                  \ts -> case (Strip.deannotateType (Core.typeSchemeBody ts)) of
                    Core.TypeRecord _ -> True
                    Core.TypeUnion _ -> True
                    Core.TypeWrap _ -> True
                    _ -> False
          badVars =
                  Sets.fromList (Lists.filter (\v -> Optionals.cases (Lexical.dereferenceSchemaType v (Graph.graphSchemaTypes tx)) False isNominal) (Sets.toList suspectVars))
          badPairs = Lists.filter (\p -> Sets.member (Pairs.first p) badVars) (Maps.toList s)
          printPair = \p -> Strings.cat2 (Strings.cat2 (Core.unName (Pairs.first p)) " --> ") (ShowCore.type_ (Pairs.second p))
      in (Logic.ifElse (Sets.null badVars) (Right subst) (Left (Errors.ErrorChecking (Checking.CheckingErrorIncorrectUnification (Checking.IncorrectUnificationError {
        Checking.incorrectUnificationErrorSubstitution = subst})))))
-- | Check that all type variables in a type are bound. NOTE: This check is currently disabled to allow phantom type variables from polymorphic instantiation to pass through. The proper fix is to ensure `typeOf` doesn't create fresh variables for post-inference code.
checkTypeVariables :: t0 -> t1 -> ()
checkTypeVariables _tx _typ = ()
-- | Check if a type contains any type variable from the current scope
containsInScopeTypeVars :: Graph.Graph -> Core.Type -> Bool
containsInScopeTypeVars tx t =

      let vars = Graph.graphTypeVariables tx
          freeVars = Variables.freeVariablesInTypeSimple t
      in (Logic.not (Sets.null (Sets.intersection vars freeVars)))
-- | Normalize free type variables in a type to canonical names based on order of first occurrence. This allows comparing types that differ only in the naming of free type variables.
normalizeTypeFreeVars :: Core.Type -> Core.Type
normalizeTypeFreeVars typ =

      let collectVars =
              \acc -> \t -> case t of
                Core.TypeVariable v0 -> Logic.ifElse (Maps.member v0 acc) acc (Maps.insert v0 (Core.Name (Strings.cat2 "_tv" (Literals.showInt32 (Maps.size acc)))) acc)
                _ -> acc
          subst = Rewriting.foldOverType Coders.TraversalOrderPre collectVars Maps.empty typ
      in (Variables.substituteTypeVariables subst typ)
-- | Get the bound types from a graph as a type environment
toFContext :: Graph.Graph -> M.Map Core.Name Core.Type
toFContext cx = Maps.map Scoping.typeSchemeToFType (Graph.graphBoundTypes cx)
-- | Check whether two lists of types are effectively equal, disregarding type aliases
typeListsEffectivelyEqual :: Graph.Graph -> [Core.Type] -> [Core.Type] -> Bool
typeListsEffectivelyEqual tx tlist1 tlist2 =
    Logic.ifElse (Equality.equal (Lists.length tlist1) (Lists.length tlist2)) (Lists.foldl Logic.and True (Lists.zipWith (typesEffectivelyEqual tx) tlist1 tlist2)) False
-- | Given a type context, reconstruct the type of a System F term
typeOf :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.Term -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOf cx tx typeArgs term =

      let cx1 = cx
      in case term of
        Core.TermAnnotated v0 -> typeOfAnnotatedTerm cx1 tx typeArgs v0
        Core.TermApplication v0 -> typeOfApplication cx1 tx typeArgs v0
        Core.TermCases v0 -> typeOfCaseStatement cx1 tx typeArgs v0
        Core.TermEither v0 -> typeOfEither cx1 tx typeArgs v0
        Core.TermLambda v0 -> typeOfLambda cx1 tx typeArgs v0
        Core.TermLet v0 -> typeOfLet cx1 tx typeArgs v0
        Core.TermList v0 -> typeOfList cx1 tx typeArgs v0
        Core.TermLiteral v0 -> typeOfLiteral cx1 tx typeArgs v0
        Core.TermMap v0 -> typeOfMap cx1 tx typeArgs v0
        Core.TermOptional v0 -> typeOfMaybe cx1 tx typeArgs v0
        Core.TermPair v0 -> typeOfPair cx1 tx typeArgs v0
        Core.TermProject v0 -> typeOfProjection cx1 tx typeArgs v0
        Core.TermRecord v0 -> typeOfRecord cx1 tx typeArgs v0
        Core.TermSet v0 -> typeOfSet cx1 tx typeArgs v0
        Core.TermTypeApplication v0 -> typeOfTypeApplication cx1 tx typeArgs v0
        Core.TermTypeLambda v0 -> typeOfTypeLambda cx1 tx typeArgs v0
        Core.TermInject v0 -> typeOfInjection cx1 tx typeArgs v0
        Core.TermUnit -> typeOfUnit cx1 tx typeArgs
        Core.TermUnwrap v0 -> typeOfUnwrap cx1 tx typeArgs v0
        Core.TermVariable v0 -> typeOfVariable cx1 tx typeArgs v0
        Core.TermWrap v0 -> typeOfWrappedTerm cx1 tx typeArgs v0
        _ -> Left (Errors.ErrorChecking (Checking.CheckingErrorUnsupportedTermVariant (Checking.UnsupportedTermVariantError {
          Checking.unsupportedTermVariantErrorTermVariant = (Reflect.termVariant term)})))
-- | Reconstruct the type of an annotated term (Either/InferenceContext version)
typeOfAnnotatedTerm :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.AnnotatedTerm -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfAnnotatedTerm cx tx typeArgs at = typeOf cx tx typeArgs (Core.annotatedTermBody at)
-- | Reconstruct the type of an application term (Either/InferenceContext version)
typeOfApplication :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.Application -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfApplication cx tx typeArgs app =

      let fun = Core.applicationFunction app
          arg = Core.applicationArgument app
          tryType =
                  \cx0 -> \tfun -> \targ -> case tfun of
                    Core.TypeForall v0 -> tryType cx0 (Core.forallTypeBody v0) targ
                    Core.TypeFunction v0 ->
                      let dom = Core.functionTypeDomain v0
                          cod = Core.functionTypeCodomain v0
                      in (Logic.ifElse (typesEffectivelyEqual tx dom targ) (Right (cod, cx0)) (Left (Errors.ErrorChecking (Checking.CheckingErrorTypeMismatch (Checking.TypeMismatchError {
                        Checking.typeMismatchErrorExpectedType = dom,
                        Checking.typeMismatchErrorActualType = targ})))))
                    Core.TypeVariable _ ->
                      let nameResult = Names.freshName cx0
                          freshN = Pairs.first nameResult
                          cx1 = Pairs.second nameResult
                      in (Right (Core.TypeVariable freshN, cx1))
                    _ -> Left (Errors.ErrorChecking (Checking.CheckingErrorNotAFunctionType (Checking.NotAFunctionTypeError {
                      Checking.notAFunctionTypeErrorType = tfun})))
      in (Eithers.bind (typeOf cx tx [] fun) (\result1 ->
        let tfun = Pairs.first result1
            cx2 = Pairs.second result1
        in (Eithers.bind (typeOf cx2 tx [] arg) (\result2 ->
          let targ = Pairs.first result2
              cx3 = Pairs.second result2
          in (Eithers.bind (tryType cx3 tfun targ) (\result3 ->
            let t = Pairs.first result3
                cx4 = Pairs.second result3
            in (Eithers.bind (applyTypeArgumentsToType cx4 tx typeArgs t) (\applied -> Right (applied, cx4)))))))))
-- | Reconstruct the type of a case statement (Either/InferenceContext version)
typeOfCaseStatement :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.CaseStatement -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfCaseStatement cx tx typeArgs cs =

      let tname = Core.caseStatementTypeName cs
          dflt = Core.caseStatementDefault cs
          cases = Core.caseStatementCases cs
          cterms = Lists.map Core.caseAlternativeHandler cases
      in (Eithers.bind (Eithers.mapOptional (\e -> typeOf cx tx [] e) dflt) (\dfltResult ->
        let tdflt = Optionals.map Pairs.first dfltResult
            cx2 = Optionals.cases dfltResult cx Pairs.second
            foldResult =
                    Lists.foldl (\acc -> \term -> Eithers.bind acc (\accR ->
                      let types = Pairs.first accR
                          cxA = Pairs.second accR
                      in (Eithers.bind (typeOf cxA tx [] term) (\tResult ->
                        let t = Pairs.first tResult
                            cxB = Pairs.second tResult
                        in (Right (Lists.concat2 types (Lists.pure t), cxB)))))) (Right ([], cx2)) cterms
        in (Eithers.bind foldResult (\foldR ->
          let tcterms = Pairs.first foldR
              cx3 = Pairs.second foldR
              fcodsResult =
                      Lists.foldl (\acc -> \t -> Eithers.bind acc (\accR ->
                        let cods = Pairs.first accR
                        in (Eithers.bind (ExtractCore.functionType t) (\ft -> Right (Lists.concat2 cods (Lists.pure (Core.functionTypeCodomain ft)), cx3))))) (Right ([], cx3)) tcterms
          in (Eithers.bind fcodsResult (\fcodsR ->
            let fcods = Pairs.first fcodsR
                cods = Optionals.cat (Lists.cons tdflt (Lists.map Optionals.pure fcods))
            in (Eithers.bind (checkSameType cx3 tx "case branches" cods) (\cod -> Right (
              Core.TypeFunction (Core.FunctionType {
                Core.functionTypeDomain = (Resolution.nominalApplication tname typeArgs),
                Core.functionTypeCodomain = cod}),
              cx3)))))))))
-- | Reconstruct the type of an either value (Either/InferenceContext version)
typeOfEither :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Either Core.Term Core.Term -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfEither cx tx typeArgs et =

      let n = Lists.length typeArgs
          arityErr =
                  Left (Errors.ErrorChecking (Checking.CheckingErrorTypeArityMismatch (Checking.TypeArityMismatchError {
                    Checking.typeArityMismatchErrorType = (Core.TypeEither (Core.EitherType {
                      Core.eitherTypeLeft = Core.TypeUnit,
                      Core.eitherTypeRight = Core.TypeUnit})),
                    Checking.typeArityMismatchErrorExpectedArity = 2,
                    Checking.typeArityMismatchErrorActualArity = n,
                    Checking.typeArityMismatchErrorTypeArguments = typeArgs})))
      in (Optionals.cases (Lists.uncons typeArgs) arityErr (\uc0 ->
        let ta0 = Pairs.first uc0
        in (Optionals.cases (Lists.uncons (Pairs.second uc0)) arityErr (\uc1 ->
          let ta1 = Pairs.first uc1
          in (Logic.ifElse (Equality.equal n 2) (Eithers.either (\leftTerm -> Eithers.bind (typeOf cx tx [] leftTerm) (\result ->
            let leftType = Pairs.first result
                cx2 = Pairs.second result
            in (Right (
              Core.TypeEither (Core.EitherType {
                Core.eitherTypeLeft = leftType,
                Core.eitherTypeRight = ta1}),
              cx2)))) (\rightTerm -> Eithers.bind (typeOf cx tx [] rightTerm) (\result ->
            let rightType = Pairs.first result
                cx2 = Pairs.second result
            in (Right (
              Core.TypeEither (Core.EitherType {
                Core.eitherTypeLeft = ta0,
                Core.eitherTypeRight = rightType}),
              cx2)))) et) arityErr)))))
-- | Reconstruct the type of a union injection (Either/InferenceContext version)
typeOfInjection :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.Injection -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfInjection cx tx typeArgs injection =

      let tname = Core.injectionTypeName injection
          field = Core.injectionField injection
          fname = Core.fieldName field
          fterm = Core.fieldTerm field
      in (Eithers.bind (Resolution.requireSchemaType cx (Graph.graphSchemaTypes tx) tname) (\schemaResult ->
        let schemaType = Pairs.first schemaResult
            cx2 = Pairs.second schemaResult
            svars = Core.typeSchemeVariables schemaType
            sbody = Core.typeSchemeBody schemaType
        in (Eithers.bind (ExtractCore.unionType tname sbody) (\sfields -> Eithers.bind (Resolution.findFieldType cx2 fname sfields) (\ftyp -> Right (Resolution.nominalApplication tname typeArgs, cx2))))))
-- | Reconstruct the type of a lambda function (Either/InferenceContext version)
typeOfLambda :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.Lambda -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfLambda cx tx typeArgs l =

      let v = Core.lambdaParameter l
          mdom = Core.lambdaDomain l
          body = Core.lambdaBody l
      in (Eithers.bind (Optionals.cases mdom (Left (Errors.ErrorChecking (Checking.CheckingErrorUntypedLambda (Checking.UntypedLambdaError {
      })))) (\dom ->
        let types2 = Maps.insert v (Scoping.fTypeToTypeScheme dom) (Graph.graphBoundTypes tx)
        in (Eithers.bind (typeOf cx (Graph.Graph {
          Graph.graphBoundTerms = (Graph.graphBoundTerms tx),
          Graph.graphBoundTypes = types2,
          Graph.graphClassConstraints = (Graph.graphClassConstraints tx),
          Graph.graphLambdaVariables = (Graph.graphLambdaVariables tx),
          Graph.graphMetadata = (Graph.graphMetadata tx),
          Graph.graphPrimitives = (Graph.graphPrimitives tx),
          Graph.graphSchemaTypes = (Graph.graphSchemaTypes tx),
          Graph.graphTypeVariables = (Graph.graphTypeVariables tx)}) [] body) (\codResult ->
          let cod = Pairs.first codResult
              cx2 = Pairs.second codResult
          in (Right (
            Core.TypeFunction (Core.FunctionType {
              Core.functionTypeDomain = dom,
              Core.functionTypeCodomain = cod}),
            cx2)))))) (\tbodyResult ->
        let tbody = Pairs.first tbodyResult
            cx3 = Pairs.second tbodyResult
        in (Eithers.bind (applyTypeArgumentsToType cx3 tx typeArgs tbody) (\applied -> Right (applied, cx3)))))
-- | Reconstruct the type of a let binding (Either/InferenceContext version)
typeOfLet :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.Let -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfLet cx tx typeArgs letTerm =

      let bs = Core.letBindings letTerm
          body = Core.letBody letTerm
          bnames = Lists.map Core.bindingName bs
          bindingType =
                  \b -> Optionals.cases (Core.bindingTypeScheme b) (Left (Errors.ErrorChecking (Checking.CheckingErrorUntypedLetBinding (Checking.UntypedLetBindingError {
                    Checking.untypedLetBindingErrorBinding = b})))) (\ts -> Right (Scoping.typeSchemeToFType ts))
          btypesResult =
                  Lists.foldl (\acc -> \b -> Eithers.bind acc (\accR ->
                    let types = Pairs.first accR
                    in (Eithers.bind (bindingType b) (\btype -> Right (Lists.concat2 types (Lists.pure btype), ()))))) (Right ([], ())) bs
      in (Eithers.bind btypesResult (\btypesR ->
        let btypes = Pairs.first btypesR
            tx2 =
                    Graph.Graph {
                      Graph.graphBoundTerms = (Graph.graphBoundTerms tx),
                      Graph.graphBoundTypes = (Maps.union (Maps.fromList (Lists.zip bnames (Lists.map Scoping.fTypeToTypeScheme btypes))) (Graph.graphBoundTypes tx)),
                      Graph.graphClassConstraints = (Graph.graphClassConstraints tx),
                      Graph.graphLambdaVariables = (Graph.graphLambdaVariables tx),
                      Graph.graphMetadata = (Graph.graphMetadata tx),
                      Graph.graphPrimitives = (Graph.graphPrimitives tx),
                      Graph.graphSchemaTypes = (Graph.graphSchemaTypes tx),
                      Graph.graphTypeVariables = (Graph.graphTypeVariables tx)}
        in (Eithers.bind (typeOf cx tx2 [] body) (\tResult ->
          let t = Pairs.first tResult
              cx2 = Pairs.second tResult
          in (Eithers.bind (applyTypeArgumentsToType cx2 tx typeArgs t) (\applied -> Right (applied, cx2)))))))
-- | Reconstruct the type of a list (Either/InferenceContext version)
typeOfList :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> [Core.Term] -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfList cx tx typeArgs els =

      let listArityErr =
              Left (Errors.ErrorChecking (Checking.CheckingErrorTypeArityMismatch (Checking.TypeArityMismatchError {
                Checking.typeArityMismatchErrorType = (Core.TypeList Core.TypeUnit),
                Checking.typeArityMismatchErrorExpectedArity = 1,
                Checking.typeArityMismatchErrorActualArity = (Lists.length typeArgs),
                Checking.typeArityMismatchErrorTypeArguments = typeArgs})))
      in (Logic.ifElse (Lists.null els) (Logic.ifElse (Equality.equal (Lists.length typeArgs) 1) (Optionals.cases (Lists.maybeHead typeArgs) listArityErr (\ta0 -> Right (Core.TypeList ta0, cx))) listArityErr) (
        let foldResult =
                Lists.foldl (\acc -> \term -> Eithers.bind acc (\accR ->
                  let types = Pairs.first accR
                      cxA = Pairs.second accR
                  in (Eithers.bind (typeOf cxA tx [] term) (\tResult ->
                    let t = Pairs.first tResult
                        cxB = Pairs.second tResult
                    in (Right (Lists.concat2 types (Lists.pure t), cxB)))))) (Right ([], cx)) els
        in (Eithers.bind foldResult (\foldR ->
          let eltypes = Pairs.first foldR
              cx2 = Pairs.second foldR
          in (Eithers.bind (checkSameType cx2 tx "list elements" eltypes) (\unifiedType -> Right (Core.TypeList unifiedType, cx2)))))))
-- | Reconstruct the type of a literal (Either/InferenceContext version)
typeOfLiteral :: t0 -> Graph.Graph -> [Core.Type] -> Core.Literal -> Either Errors.Error (Core.Type, t0)
typeOfLiteral cx tx typeArgs lit =

      let t = Core.TypeLiteral (Reflect.literalType lit)
      in (Eithers.bind (applyTypeArgumentsToType cx tx typeArgs t) (\applied -> Right (applied, cx)))
-- | Reconstruct the type of a map (Either/InferenceContext version)
typeOfMap :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> M.Map Core.Term Core.Term -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfMap cx tx typeArgs m =

      let mapArityErr =
              Left (Errors.ErrorChecking (Checking.CheckingErrorTypeArityMismatch (Checking.TypeArityMismatchError {
                Checking.typeArityMismatchErrorType = (Core.TypeMap (Core.MapType {
                  Core.mapTypeKeys = Core.TypeUnit,
                  Core.mapTypeValues = Core.TypeUnit})),
                Checking.typeArityMismatchErrorExpectedArity = 2,
                Checking.typeArityMismatchErrorActualArity = (Lists.length typeArgs),
                Checking.typeArityMismatchErrorTypeArguments = typeArgs})))
      in (Logic.ifElse (Maps.null m) (Logic.ifElse (Equality.equal (Lists.length typeArgs) 2) (Optionals.cases (Lists.uncons typeArgs) mapArityErr (\uc0 ->
        let ta0 = Pairs.first uc0
        in (Optionals.cases (Lists.uncons (Pairs.second uc0)) mapArityErr (\uc1 ->
          let ta1 = Pairs.first uc1
          in (Right (
            Core.TypeMap (Core.MapType {
              Core.mapTypeKeys = ta0,
              Core.mapTypeValues = ta1}),
            cx)))))) mapArityErr) (
        let pairs = Maps.toList m
            keyFoldResult =
                    Lists.foldl (\acc -> \p -> Eithers.bind acc (\accR ->
                      let types = Pairs.first accR
                          cxA = Pairs.second accR
                      in (Eithers.bind (typeOf cxA tx [] (Pairs.first p)) (\tResult ->
                        let t = Pairs.first tResult
                            cxB = Pairs.second tResult
                        in (Right (Lists.concat2 types (Lists.pure t), cxB)))))) (Right ([], cx)) pairs
        in (Eithers.bind keyFoldResult (\keyFoldR ->
          let keyTypes = Pairs.first keyFoldR
              cx2 = Pairs.second keyFoldR
          in (Eithers.bind (checkSameType cx2 tx "map keys" keyTypes) (\kt ->
            let valFoldResult =
                    Lists.foldl (\acc -> \p -> Eithers.bind acc (\accR ->
                      let types = Pairs.first accR
                          cxA = Pairs.second accR
                      in (Eithers.bind (typeOf cxA tx [] (Pairs.second p)) (\tResult ->
                        let t = Pairs.first tResult
                            cxB = Pairs.second tResult
                        in (Right (Lists.concat2 types (Lists.pure t), cxB)))))) (Right ([], cx2)) pairs
            in (Eithers.bind valFoldResult (\valFoldR ->
              let valTypes = Pairs.first valFoldR
                  cx3 = Pairs.second valFoldR
              in (Eithers.bind (checkSameType cx3 tx "map values" valTypes) (\vt -> Eithers.bind (applyTypeArgumentsToType cx3 tx typeArgs (Core.TypeMap (Core.MapType {
                Core.mapTypeKeys = kt,
                Core.mapTypeValues = vt}))) (\applied -> Right (applied, cx3))))))))))))
-- | Reconstruct the type of an optional value (Either/InferenceContext version)
typeOfMaybe :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Maybe Core.Term -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfMaybe cx tx typeArgs mt =

      let forNothing =

                let n = Lists.length typeArgs
                    maybeArityErr =
                            Left (Errors.ErrorChecking (Checking.CheckingErrorTypeArityMismatch (Checking.TypeArityMismatchError {
                              Checking.typeArityMismatchErrorType = (Core.TypeOptional Core.TypeUnit),
                              Checking.typeArityMismatchErrorExpectedArity = 1,
                              Checking.typeArityMismatchErrorActualArity = n,
                              Checking.typeArityMismatchErrorTypeArguments = typeArgs})))
                in (Logic.ifElse (Equality.equal n 1) (Optionals.cases (Lists.maybeHead typeArgs) maybeArityErr (\ta0 -> Right (Core.TypeOptional ta0, cx))) maybeArityErr)
          forJust =
                  \term -> Eithers.bind (typeOf cx tx [] term) (\tResult ->
                    let termType = Pairs.first tResult
                        cx2 = Pairs.second tResult
                        t = Core.TypeOptional termType
                    in (Eithers.bind (applyTypeArgumentsToType cx2 tx typeArgs t) (\applied -> Right (applied, cx2))))
      in (Optionals.cases mt forNothing forJust)
-- | Reconstruct the type of a pair (Either/InferenceContext version)
typeOfPair :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> (Core.Term, Core.Term) -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfPair cx tx typeArgs p =

      let n = Lists.length typeArgs
      in (Logic.ifElse (Equality.equal n 2) (
        let pairFst = Pairs.first p
            pairSnd = Pairs.second p
        in (Eithers.bind (typeOf cx tx [] pairFst) (\result1 ->
          let firstType = Pairs.first result1
              cx2 = Pairs.second result1
          in (Eithers.bind (typeOf cx2 tx [] pairSnd) (\result2 ->
            let secondType = Pairs.first result2
                cx3 = Pairs.second result2
            in (Right (
              Core.TypePair (Core.PairType {
                Core.pairTypeFirst = firstType,
                Core.pairTypeSecond = secondType}),
              cx3))))))) (Left (Errors.ErrorChecking (Checking.CheckingErrorTypeArityMismatch (Checking.TypeArityMismatchError {
        Checking.typeArityMismatchErrorType = (Core.TypePair (Core.PairType {
          Core.pairTypeFirst = Core.TypeUnit,
          Core.pairTypeSecond = Core.TypeUnit})),
        Checking.typeArityMismatchErrorExpectedArity = 2,
        Checking.typeArityMismatchErrorActualArity = n,
        Checking.typeArityMismatchErrorTypeArguments = typeArgs})))))
-- | Reconstruct the type of a primitive function (Either/InferenceContext version)
typeOfPrimitive :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.Name -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfPrimitive cx tx typeArgs name =

      let rawTs =
              Optionals.map (\_p -> Scoping.termSignatureToTypeScheme (Packaging.primitiveDefinitionSignature (Graph.primitiveDefinition _p))) (Maps.lookup name (Graph.graphPrimitives tx))
      in (Optionals.cases rawTs (Left (Errors.ErrorUndefinedTermVariable (ErrorCore.UndefinedTermVariableError {
        ErrorCore.undefinedTermVariableErrorLocation = (Paths.SubtermPath []),
        ErrorCore.undefinedTermVariableErrorName = name}))) (\tsRaw ->
        let instResult = Resolution.instantiateTypeScheme cx tsRaw
            ts = Pairs.first instResult
            cx2 = Pairs.second instResult
            t = Scoping.typeSchemeToFType ts
        in (Eithers.bind (applyTypeArgumentsToType cx2 tx typeArgs t) (\applied -> Right (applied, cx2)))))
-- | Reconstruct the type of a record projection (Either/InferenceContext version)
typeOfProjection :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.Projection -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfProjection cx tx typeArgs p =

      let tname = Core.projectionTypeName p
          fname = Core.projectionFieldName p
      in (Eithers.bind (Resolution.requireSchemaType cx (Graph.graphSchemaTypes tx) tname) (\schemaResult ->
        let schemaType = Pairs.first schemaResult
            cx2 = Pairs.second schemaResult
            svars = Core.typeSchemeVariables schemaType
            sbody = Core.typeSchemeBody schemaType
        in (Eithers.bind (ExtractCore.recordType tname sbody) (\sfields -> Eithers.bind (Resolution.findFieldType cx2 fname sfields) (\ftyp ->
          let subst = Typing.TypeSubst (Maps.fromList (Lists.zip svars typeArgs))
              sftyp = Substitution.substInType subst ftyp
          in (Right (
            Core.TypeFunction (Core.FunctionType {
              Core.functionTypeDomain = (Resolution.nominalApplication tname typeArgs),
              Core.functionTypeCodomain = sftyp}),
            cx2)))))))
-- | Reconstruct the type of a record (Either/InferenceContext version)
typeOfRecord :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.Record -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfRecord cx tx typeArgs record =

      let tname = Core.recordTypeName record
          fields = Core.recordFields record
          foldResult =
                  Lists.foldl (\acc -> \term -> Eithers.bind acc (\accR ->
                    let types = Pairs.first accR
                        cxA = Pairs.second accR
                    in (Eithers.bind (typeOf cxA tx [] term) (\tResult ->
                      let t = Pairs.first tResult
                          cxB = Pairs.second tResult
                      in (Right (Lists.concat2 types (Lists.pure t), cxB)))))) (Right ([], cx)) (Lists.map Core.fieldTerm fields)
      in (Eithers.bind foldResult (\foldR ->
        let cx2 = Pairs.second foldR
        in (Right (Resolution.nominalApplication tname typeArgs, cx2))))
-- | Reconstruct the type of a set (Either/InferenceContext version)
typeOfSet :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> S.Set Core.Term -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfSet cx tx typeArgs els =

      let setArityErr =
              Left (Errors.ErrorChecking (Checking.CheckingErrorTypeArityMismatch (Checking.TypeArityMismatchError {
                Checking.typeArityMismatchErrorType = (Core.TypeSet Core.TypeUnit),
                Checking.typeArityMismatchErrorExpectedArity = 1,
                Checking.typeArityMismatchErrorActualArity = (Lists.length typeArgs),
                Checking.typeArityMismatchErrorTypeArguments = typeArgs})))
      in (Logic.ifElse (Sets.null els) (Logic.ifElse (Equality.equal (Lists.length typeArgs) 1) (Optionals.cases (Lists.maybeHead typeArgs) setArityErr (\ta0 -> Right (Core.TypeSet ta0, cx))) setArityErr) (
        let foldResult =
                Lists.foldl (\acc -> \term -> Eithers.bind acc (\accR ->
                  let types = Pairs.first accR
                      cxA = Pairs.second accR
                  in (Eithers.bind (typeOf cxA tx [] term) (\tResult ->
                    let t = Pairs.first tResult
                        cxB = Pairs.second tResult
                    in (Right (Lists.concat2 types (Lists.pure t), cxB)))))) (Right ([], cx)) (Sets.toList els)
        in (Eithers.bind foldResult (\foldR ->
          let eltypes = Pairs.first foldR
              cx2 = Pairs.second foldR
          in (Eithers.bind (checkSameType cx2 tx "set elements" eltypes) (\unifiedType -> Right (Core.TypeSet unifiedType, cx2)))))))
-- | Check the type of a term
typeOfTerm :: Typing.InferenceContext -> Graph.Graph -> Core.Term -> Either Errors.Error Core.Type
typeOfTerm cx g term = Eithers.map Pairs.first (typeOf cx g [] term)
-- | Reconstruct the type of a type application term (Either/InferenceContext version)
typeOfTypeApplication :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.TypeApplicationTerm -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfTypeApplication cx tx typeArgs tyapp =

      let body = Core.typeApplicationTermBody tyapp
          t = Core.typeApplicationTermType tyapp
      in (typeOf cx tx (Lists.cons t typeArgs) body)
-- | Reconstruct the type of a type lambda (type abstraction) term (Either/InferenceContext version)
typeOfTypeLambda :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.TypeLambda -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfTypeLambda cx tx typeArgs tl =

      let v = Core.typeLambdaParameter tl
          body = Core.typeLambdaBody tl
          vars = Graph.graphTypeVariables tx
          tx2 =
                  Graph.Graph {
                    Graph.graphBoundTerms = (Graph.graphBoundTerms tx),
                    Graph.graphBoundTypes = (Graph.graphBoundTypes tx),
                    Graph.graphClassConstraints = (Graph.graphClassConstraints tx),
                    Graph.graphLambdaVariables = (Graph.graphLambdaVariables tx),
                    Graph.graphMetadata = (Graph.graphMetadata tx),
                    Graph.graphPrimitives = (Graph.graphPrimitives tx),
                    Graph.graphSchemaTypes = (Graph.graphSchemaTypes tx),
                    Graph.graphTypeVariables = (Sets.insert v vars)}
      in (Eithers.bind (typeOf cx tx2 [] body) (\result1 ->
        let t1 = Pairs.first result1
            cx2 = Pairs.second result1
        in (Eithers.bind (applyTypeArgumentsToType cx2 tx typeArgs (Core.TypeForall (Core.ForallType {
          Core.forallTypeParameter = v,
          Core.forallTypeBody = t1}))) (\applied -> Right (applied, cx2)))))
-- | Reconstruct the type of the unit term (Either/InferenceContext version)
typeOfUnit :: t0 -> Graph.Graph -> [Core.Type] -> Either Errors.Error (Core.Type, t0)
typeOfUnit cx tx typeArgs =
    Eithers.bind (applyTypeArgumentsToType cx tx typeArgs Core.TypeUnit) (\applied -> Right (applied, cx))
-- | Reconstruct the type of an unwrap operation (Either/InferenceContext version)
typeOfUnwrap :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.Name -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfUnwrap cx tx typeArgs tname =
    Eithers.bind (Resolution.requireSchemaType cx (Graph.graphSchemaTypes tx) tname) (\schemaResult ->
      let schemaType = Pairs.first schemaResult
          cx2 = Pairs.second schemaResult
          svars = Core.typeSchemeVariables schemaType
          sbody = Core.typeSchemeBody schemaType
      in (Eithers.bind (ExtractCore.wrappedType tname sbody) (\wrapped ->
        let subst = Typing.TypeSubst (Maps.fromList (Lists.zip svars typeArgs))
            swrapped = Substitution.substInType subst wrapped
        in (Right (
          Core.TypeFunction (Core.FunctionType {
            Core.functionTypeDomain = (Resolution.nominalApplication tname typeArgs),
            Core.functionTypeCodomain = swrapped}),
          cx2)))))
-- | Reconstruct the type of a variable (Either/InferenceContext version)
typeOfVariable :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.Name -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfVariable cx tx typeArgs name =

      let rawTypeScheme = Maps.lookup name (Graph.graphBoundTypes tx)
          forScheme =
                  \ts ->
                    let tResult =
                            Logic.ifElse (Lists.null typeArgs) (Resolution.instantiateType cx (Scoping.typeSchemeToFType ts)) (Scoping.typeSchemeToFType ts, cx)
                        t = Pairs.first tResult
                        cx2 = Pairs.second tResult
                    in (Eithers.bind (applyTypeArgumentsToType cx2 tx typeArgs t) (\applied -> Right (applied, cx2)))
      in (Optionals.cases rawTypeScheme (Optionals.cases (Optionals.map (\_p -> Scoping.termSignatureToTypeScheme (Packaging.primitiveDefinitionSignature (Graph.primitiveDefinition _p))) (Maps.lookup name (Graph.graphPrimitives tx))) (Left (Errors.ErrorUntypedTermVariable (ErrorCore.UntypedTermVariableError {
        ErrorCore.untypedTermVariableErrorLocation = (Paths.SubtermPath []),
        ErrorCore.untypedTermVariableErrorName = name}))) forScheme) forScheme)
-- | Reconstruct the type of a wrapped term (Either/InferenceContext version)
typeOfWrappedTerm :: Typing.InferenceContext -> Graph.Graph -> [Core.Type] -> Core.WrappedTerm -> Either Errors.Error (Core.Type, Typing.InferenceContext)
typeOfWrappedTerm cx tx typeArgs wt =

      let tname = Core.wrappedTermTypeName wt
          body = Core.wrappedTermBody wt
      in (Eithers.bind (typeOf cx tx [] body) (\result ->
        let cx2 = Pairs.second result
        in (Right (Resolution.nominalApplication tname typeArgs, cx2))))
-- | Check whether a list of types are effectively equal, disregarding type aliases and free type variable naming. Also treats free type variables (not in schema) as wildcards, since inference has already verified consistency.
typesAllEffectivelyEqual :: Graph.Graph -> [Core.Type] -> Bool
typesAllEffectivelyEqual tx tlist =

      let types = Graph.graphSchemaTypes tx
          containsFreeVar =
                  \t ->
                    let allVars = Variables.freeVariablesInTypeSimple t
                        schemaNames = Sets.fromList (Maps.keys types)
                    in (Logic.not (Sets.null (Sets.difference allVars schemaNames)))
          anyContainsFreeVar = Lists.foldl (\acc -> \t -> Logic.or acc (containsFreeVar t)) False tlist
      in (Logic.ifElse anyContainsFreeVar True (Logic.ifElse (allEqual (Lists.map (\t -> normalizeTypeFreeVars t) tlist)) True (allEqual (Lists.map (\t -> normalizeTypeFreeVars (Strip.deannotateTypeRecursive (Dependencies.replaceTypedefs types t))) tlist))))
-- | Check whether two types are effectively equal, disregarding type aliases, forall quantifiers, and treating in-scope type variables as wildcards
typesEffectivelyEqual :: Graph.Graph -> Core.Type -> Core.Type -> Bool
typesEffectivelyEqual tx t1 t2 =
    Logic.or (containsInScopeTypeVars tx t1) (Logic.or (containsInScopeTypeVars tx t2) (typesAllEffectivelyEqual tx [
      Resolution.fullyStripAndNormalizeType t1,
      (Resolution.fullyStripAndNormalizeType t2)]))