Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions backend/src/Builtins/Builtins.Http.Client/Libs/HttpClient.fs
Original file line number Diff line number Diff line change
Expand Up @@ -689,9 +689,11 @@ let fns (config : Configuration) : List<BuiltInFn> =
FQFnName.fqPackage (
PackageRefs.Fn.Stdlib.HttpClient.request ()
),
None,
2,
"headers",
VT.list (VT.tuple VT.string VT.string []),
None,
Dval.toValueType notAPair,
notAPair
)
Expand Down Expand Up @@ -821,9 +823,11 @@ let fns (config : Configuration) : List<BuiltInFn> =
FQFnName.fqPackage (
PackageRefs.Fn.Stdlib.HttpClient.stream ()
),
None,
2,
"headers",
VT.list (VT.tuple VT.string VT.string []),
None,
Dval.toValueType notAPair,
notAPair
)
Expand Down
3 changes: 2 additions & 1 deletion backend/src/Builtins/Builtins.Pure/Libs/Float.fs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,8 @@ let fns () : List<BuiltInFn> =
(TCustomType(
{ originalName = []
resolved =
Ok(FQTypeName.fqPackage (PackageRefs.Type.Stdlib.floatParseError ())) },
Ok(FQTypeName.fqPackage (PackageRefs.Type.Stdlib.floatParseError ()))
location = None },
[]
))
description =
Expand Down
3 changes: 2 additions & 1 deletion backend/src/Builtins/Builtins.Pure/Libs/Int128.fs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,8 @@ let fns () : List<BuiltInFn> =
resolved =
Ok(
FQTypeName.fqPackage (PackageRefs.Type.Stdlib.int128ParseError ())
) },
)
location = None },
[]
))
description = "Returns the <type Int128> value of a <type String>"
Expand Down
9 changes: 8 additions & 1 deletion backend/src/Builtins/Builtins.Pure/Libs/NoModule.fs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,14 @@ let rec equals (a : Dval) (b : Dval) : bool =
// equality needs lambda-internal-state work. Today this is
// "same-source-position lambdas compare equal."
| AppLambda a, AppLambda b -> a.exprId = b.exprId
| AppNamedFn a, AppNamedFn b -> a = b
| AppNamedFn a, AppNamedFn b ->
// `location` is excluded: it records how the function was named at the
// reference site (for error messages), not its identity. Two references
// to the same function by different names are the same function.
a.name = b.name
&& a.typeArgs = b.typeArgs
&& a.argsSoFar = b.argsSoFar
&& a.typeSymbolTable = b.typeSymbolTable
| _ -> false

| DDB a, DDB b -> a = b
Expand Down
3 changes: 2 additions & 1 deletion backend/src/Builtins/Builtins.Pure/Libs/UInt128.fs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,8 @@ let fns () : List<BuiltInFn> =
resolved =
Ok(
FQTypeName.fqPackage (PackageRefs.Type.Stdlib.uint128ParseError ())
) },
)
location = None },
[]
))
description = "Returns the <type UInt128> value of a <type String>"
Expand Down
3 changes: 2 additions & 1 deletion backend/src/Builtins/Builtins.Pure/Libs/UInt64.fs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@ let fns () : List<BuiltInFn> =
resolved =
Ok(
FQTypeName.fqPackage (PackageRefs.Type.Stdlib.uint64ParseError ())
) },
)
location = None },
[]
))
description = "Returns the <type UInt64> value of a <type String>"
Expand Down
3 changes: 2 additions & 1 deletion backend/src/Builtins/Builtins.Pure/Libs/Uuid.fs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ let fns () : List<BuiltInFn> =
(TCustomType(
{ originalName = []
resolved =
Ok(FQTypeName.fqPackage (PackageRefs.Type.Stdlib.uuidParseError ())) },
Ok(FQTypeName.fqPackage (PackageRefs.Type.Stdlib.uuidParseError ()))
location = None },
[]
))
description =
Expand Down
1 change: 1 addition & 0 deletions backend/src/LibExecution/Execution.fs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ let executeFunction
let fnInstr, fnReg, rc =
let namedFn : RT.ApplicableNamedFn =
{ name = name
location = None
typeSymbolTable = Map.empty
typeArgs = typeArgs
argsSoFar = [] }
Expand Down
14 changes: 11 additions & 3 deletions backend/src/LibExecution/Interpreter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,8 @@ let rec private executeInner (exeState : ExecutionState) (vm : VMState) : Ply<Dv
Map.mergeFavoringRight
appLambda.typeSymbolTable
currentFrame.typeSymbolTable
executionPoint = Lambda(currentFrame.executionPoint, exprId) }
executionPoint = Lambda(currentFrame.executionPoint, exprId)
fnLocation = None }

if vm.stats.enabled then
vm.stats.framePushCount <- vm.stats.framePushCount + 1L
Expand Down Expand Up @@ -714,7 +715,10 @@ let rec private executeInner (exeState : ExecutionState) (vm : VMState) : Ply<Dv
|> raiseRTE

let typeCheckParam =
TypeChecker.checkFnParam exeState.types applicable.name
TypeChecker.checkFnParam
exeState.types
applicable.name
applicable.location

let mutable tst =
if Map.isEmpty applicable.typeSymbolTable then
Expand Down Expand Up @@ -890,6 +894,7 @@ let rec private executeInner (exeState : ExecutionState) (vm : VMState) : Ply<Dv
TypeChecker.checkFnResult
exeState.types
(FQFnName.Builtin fn.name)
None
tst
expectedReturnType
result
Expand Down Expand Up @@ -1059,7 +1064,8 @@ let rec private executeInner (exeState : ExecutionState) (vm : VMState) : Ply<Dv
allArgs |> List.iteri (fun i arg -> r[i] <- arg)
r
typeSymbolTable = frameTst
executionPoint = pkgEp }
executionPoint = pkgEp
fnLocation = applicable.location }
|> Some

| RaiseNRE(names, nre) -> raiseRTE (RTE.ParseTimeNameResolution(names, nre))
Expand Down Expand Up @@ -1133,7 +1139,9 @@ let rec private executeInner (exeState : ExecutionState) (vm : VMState) : Ply<Dv
return
RuntimeError.Applications.FnResultNotExpectedType(
fnName,
currentFrame.fnLocation,
expectedVT,
TypeReference.locationOf expectedReturnType,
Dval.toValueType resultOfFrame,
resultOfFrame
)
Expand Down
21 changes: 15 additions & 6 deletions backend/src/LibExecution/ProgramTypesToRuntimeTypes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,24 @@ module NameResolutionError =
| PT.NameResolutionError.NotFound -> RT.NameResolutionError.NotFound
| PT.NameResolutionError.InvalidName -> RT.NameResolutionError.InvalidName

module PackageLocation =
let toRT (l : PT.PackageLocation) : RT.PackageLocation =
{ owner = l.owner; modules = l.modules; name = l.name }

module NameResolution =
// `location` is package-store metadata — load-bearing for propagation
// rewrites (AstTransformer's byLocation substitution), SCC hash
// substitution (Canonical writer), dep-edge inserts, and deferred
// refresh. The runtime executes against already-resolved hashes and
// has no use for any of that, so we drop location at the PT→RT boundary.
// PT.NameResolution.location is package-store metadata used by package
// rewriting, hashing, dependency tracking, and deferred refresh. RT keeps it
// only so runtime errors can render the package name that was referenced.
let toRT (f : 'a -> 'b) (nr : PT.NameResolution<'a>) : RT.NameResolution<'b> =
{ originalName = nr.originalName
resolved =
match nr.resolved with
| Ok resolved -> Ok(f resolved.name)
| Error e -> Error(NameResolutionError.toRT e) }
| Error e -> Error(NameResolutionError.toRT e)
location =
match nr.resolved with
| Ok resolved -> resolved.location |> Option.map PackageLocation.toRT
| Error _ -> None }


module TypeReference =
Expand Down Expand Up @@ -745,6 +751,7 @@ module Expr =
// Create a named function reference to the current function
let namedFn : RT.ApplicableNamedFn =
{ name = FQFnName.toRT fnName
location = None
typeSymbolTable = Map.empty
typeArgs = []
argsSoFar = [] }
Expand Down Expand Up @@ -872,6 +879,7 @@ module Expr =
right.registerCount,
RT.AppNamedFn
{ name = InfixFnName.toFnName infix |> RT.FQFnName.Builtin
location = None
typeSymbolTable = Map.empty
typeArgs = []
argsSoFar = [] }
Expand Down Expand Up @@ -913,6 +921,7 @@ module Expr =
| PT.EFnName(_, { resolved = Ok resolved }) ->
let namedFn : RT.ApplicableNamedFn =
{ name = FQFnName.toRT resolved.name
location = resolved.location |> Option.map PackageLocation.toRT
typeSymbolTable = Map.empty
typeArgs = []
argsSoFar = [] }
Expand Down
1 change: 1 addition & 0 deletions backend/src/LibExecution/RTQueryCompiler.fs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ let partialEvaluate
// Load the function reference
let appFn : RT.ApplicableNamedFn =
{ name = fnName
location = None
typeSymbolTable = Map.empty
typeArgs = typeArgs
argsSoFar = [] }
Expand Down
72 changes: 66 additions & 6 deletions backend/src/LibExecution/RuntimeTypes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,24 @@ type NameResolutionError =
| NotFound
| InvalidName

/// The package location a reference resolved to (owner.modules.name). Carried
/// from PT so error messages can name the referenced item when multiple names
/// share the same hash.
type PackageLocation = { owner : string; modules : List<string>; name : string }

type NameResolution<'a> =
{ originalName : List<string>; resolved : Result<'a, NameResolutionError> }
{
originalName : List<string>
resolved : Result<'a, NameResolutionError>
/// The resolved item's location, when known (only meaningful when
/// `resolved` is `Ok`). Preserved from PT to disambiguate the rendered
/// name of structurally-identical siblings.
location : Option<PackageLocation>
}

module NameResolution =
let ok (value : 'a) : NameResolution<'a> =
{ originalName = []; resolved = Ok value }
{ originalName = []; resolved = Ok value; location = None }


/// A KnownType represents the type of a dval.
Expand Down Expand Up @@ -579,14 +591,23 @@ and LambdaImpl =


and ApplicableNamedFn =
{ name : FQFnName.FQFnName
{
name : FQFnName.FQFnName

/// The package location the function reference resolved to, when known
/// (None for built-ins / re-derived applicables). Carried so error messages
/// name the *referenced* function rather than the canonical name of a
/// structurally-identical sibling that shares its hash. Excluded from
/// equality (see `Builtins.Pure.Libs.NoModule`).
location : Option<PackageLocation>

typeSymbolTable : TypeSymbolTable

// CLEANUP maybe this could be List<ValueType>?
typeArgs : List<TypeReference>

argsSoFar : List<Dval> }
argsSoFar : List<Dval>
}

and ApplicableLambda =
{
Expand Down Expand Up @@ -994,15 +1015,27 @@ module RuntimeError =

| FnParameterNotExpectedType of
fnName : FQFnName.FQFnName *
// The package location the called function resolved to, when known.
// Like `expectedTypeLocation`, lets the message name the referenced
// function rather than a canonical sibling that shares its hash.
fnNameLocation : Option<PackageLocation> *
paramIndex : int64 *
paramName : string *
expectedType : ValueType *
// The package location the expected type resolved to, when it's a
// custom type (None otherwise). Used by error rendering to name the
// referenced type when multiple names share the same hash.
expectedTypeLocation : Option<PackageLocation> *
actualType : ValueType *
actualValue : Dval

| FnResultNotExpectedType of
fnName : FQFnName.FQFnName *
// See `fnNameLocation` on `FnParameterNotExpectedType`.
fnNameLocation : Option<PackageLocation> *
expectedType : ValueType *
// See `expectedTypeLocation` on `FnParameterNotExpectedType`.
expectedTypeLocation : Option<PackageLocation> *
actualType : ValueType *
actualValue : Dval

Expand Down Expand Up @@ -1644,6 +1677,13 @@ type CallFrame =
// so we keep only one copy of such, in the root of the VMState
executionPoint : ExecutionPoint

/// The package location the called function was referenced by, when known.
/// `executionPoint` keeps only the hash, which renders as the canonical name
/// of a structurally-identical sibling; this lets a result-type-mismatch
/// error name the function as it was actually called. None for the root
/// frame, lambdas, and built-ins.
fnLocation : Option<PackageLocation>

/// What instruction index we are currently 'at'
mutable programCounter : int

Expand Down Expand Up @@ -1759,6 +1799,7 @@ type VMState =
let rootCallFrame : CallFrame =
{ id = rootCallFrameID
executionPoint = Source
fnLocation = None
programCounter = 0
registers = Array.zeroCreate instrs.registerCount
typeSymbolTable = Map.empty
Expand Down Expand Up @@ -2015,14 +2056,16 @@ module TypeReference =
let result (t1 : TypeReference) (t2 : TypeReference) : TypeReference =
TCustomType(
{ originalName = []
resolved = Ok(FQTypeName.fqPackage (PackageRefs.Type.Stdlib.result ())) },
resolved = Ok(FQTypeName.fqPackage (PackageRefs.Type.Stdlib.result ()))
location = None },
[ t1; t2 ]
)

let option (t : TypeReference) : TypeReference =
TCustomType(
{ originalName = []
resolved = Ok(FQTypeName.fqPackage (PackageRefs.Type.Stdlib.option ())) },
resolved = Ok(FQTypeName.fqPackage (PackageRefs.Type.Stdlib.option ()))
location = None },
[ t ]
)

Expand All @@ -2039,6 +2082,23 @@ module TypeReference =
| _ -> Ply typ


/// The type's name as written at the reference site (the qualifiers), for a
/// custom type. Empty for built-in/primitive types, which carry no package
/// name. Used to report the as-written name in errors, since reducing to a
/// `ValueType` keeps only the hash (and thus the canonical sibling's name).
let originalNameOf (typeRef : TypeReference) : List<string> =
match typeRef with
| TCustomType(nr, _) -> nr.originalName
| _ -> []

/// The resolved package location of a custom type reference, when known.
/// Used by runtime error rendering.
let locationOf (typeRef : TypeReference) : Option<PackageLocation> =
match typeRef with
| TCustomType(nr, _) -> nr.location
| _ -> None


let rec toVT
(types : Types)
(tst : TypeSymbolTable)
Expand Down
Loading