123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- package checker
- import (
- "fmt"
- )
- func RequireExplicitType(t Type, info ExprInfo) *ExprError {
- if t == nil {
- return &ExprError {
- Point: info.ErrorPoint,
- Concrete: E_ExplicitTypeRequired {},
- }
- } else {
- return nil
- }
- }
- func AssignTo(expected Type, semi SemiExpr, ctx ExprContext) (Expr, *ExprError) {
- var expr, err = (func() (Expr, *ExprError) {
- switch semi_value := semi.Value.(type) {
- case TypedExpr:
- return AssignTypedTo(expected, Expr(semi_value), ctx, true)
- case UntypedLambda:
- return AssignLambdaTo(expected, semi_value, semi.Info, ctx)
- case UntypedInteger:
- return AssignIntegerTo(expected, semi_value, semi.Info, ctx)
- case SemiTypedTuple:
- return AssignTupleTo(expected, semi_value, semi.Info, ctx)
- case SemiTypedBundle:
- return AssignBundleTo(expected, semi_value, semi.Info, ctx)
- case SemiTypedArray:
- return AssignArrayTo(expected, semi_value, semi.Info, ctx)
- case SemiTypedBlock:
- return AssignBlockTo(expected, semi_value, semi.Info, ctx)
- case SemiTypedMatch:
- return AssignMatchTo(expected, semi_value, semi.Info, ctx)
- case UntypedRef:
- return AssignRefTo(expected, semi_value, semi.Info, ctx)
- case UndecidedCall:
- return AssignCallTo(expected, semi_value, semi.Info, ctx)
- default:
- panic("impossible branch")
- }
- })()
- if err != nil { return Expr{}, err }
- if ctx.InferTypeArgs {
- return Expr {
- Type: FillMarkedParams(expr.Type, ctx),
- Value: expr.Value,
- Info: expr.Info,
- }, nil
- } else {
- return expr, nil
- }
- }
- func AssignTypedTo(expected Type, expr Expr, ctx ExprContext, unbox bool) (Expr, *ExprError) {
- // TODO: update comments
- if expected == nil {
- // 1. If the expected type is not specified,
- // no further process is required.
- return expr, nil
- } else {
- // 3. Otherwise, try some implicit type conversions
- // 3.1. Define some inner functions
- // -- shortcut to produce a "not assignable" error --
- var throw = func(reason string) *ExprError {
- return &ExprError {
- Point: expr.Info.ErrorPoint,
- Concrete: E_NotAssignable {
- From: ctx.DescribeType(expr.Type),
- To: ctx.DescribeExpectedType(expected),
- Reason: reason,
- },
- }
- }
- // -- behavior of assigning a named type to an union type --
- var assign_union func(NamedType, NamedType, Union) (Expr, *ExprError)
- assign_union = func(exp NamedType, given NamedType, union Union) (Expr, *ExprError) {
- // 1. Find the given type in the list of subtypes of the union
- for index, subtype := range union.SubTypes {
- if subtype == given.Name {
- // 1.1. If found, check if type parameters are identical
- if len(exp.Args) != len(given.Args) {
- panic("something went wrong")
- }
- var L = len(exp.Args)
- for i := 0; i < L; i += 1 {
- var arg_exp = exp.Args[i]
- var arg_given = given.Args[i]
- if !(AreTypesEqualInSameCtx(arg_exp, arg_given)) {
- // 1.1.1. If not identical, throw an error.
- return Expr{}, throw("type parameters not matching")
- }
- }
- // 1.1.2. Otherwise, return a lifted value.
- return Expr {
- Type: exp,
- Value: Sum { Value: expr, Index: uint(index) },
- Info: expr.Info,
- }, nil
- }
- }
- for index, subtype := range union.SubTypes {
- var t = ctx.ModuleInfo.Types[subtype]
- var item_union, ok = t.Value.(Union)
- if ok {
- var item_expr, err = assign_union(NamedType {
- Name: subtype,
- Args: exp.Args,
- }, given, item_union)
- if err != nil { continue }
- return Expr {
- Type: exp,
- Value: Sum { Value: item_expr, Index: uint(index) },
- Info: expr.Info,
- }, nil
- }
- }
- // 1.2. Otherwise, throw an error.
- return Expr{}, throw("given type is not a subtype of the expected union type")
- }
- var compare_named func(NamedType, NamedType) (*ExprError)
- compare_named = func(E NamedType, T NamedType) (*ExprError) {
- if !(ctx.InferTypeArgs) { panic("something went wrong") }
- if E.Name != T.Name {
- return throw("")
- }
- if len(E.Args) != len(T.Args) {
- return throw("")
- }
- var L = len(T.Args)
- for i := 0; i < L; i += 1 {
- switch E_arg := E.Args[i].(type) {
- case ParameterType:
- if E_arg.BeingInferred {
- var inferred, exists = ctx.Inferred[E_arg.Index]
- if exists {
- if !AreTypesEqualInSameCtx(inferred, expected) {
- return throw(fmt.Sprintf(
- "cannot infer type parameter %s",
- ctx.InferredNames[E_arg.Index],
- ))
- }
- } else {
- ctx.Inferred[E_arg.Index] = T.Args[i]
- }
- } else {
- if !(AreTypesEqualInSameCtx(E.Args[i], T.Args[i])) {
- return throw("")
- }
- }
- case NamedType:
- switch T_arg := T.Args[i].(type) {
- case NamedType:
- var err = compare_named(E_arg, T_arg)
- if err != nil { return err }
- default:
- if !(AreTypesEqualInSameCtx(E.Args[i], T.Args[i])) {
- return throw("")
- }
- }
- default:
- if !(AreTypesEqualInSameCtx(E.Args[i], T.Args[i])) {
- return throw("")
- }
- }
- }
- return nil
- }
- switch E := expected.(type) {
- case ParameterType:
- if ctx.InferTypeArgs && E.BeingInferred {
- var inferred, exists = ctx.Inferred[E.Index]
- if exists {
- if AreTypesEqualInSameCtx(inferred, expected) {
- return expr, nil
- } else {
- return Expr{}, throw(fmt.Sprintf (
- "cannot infer type parameter %s",
- ctx.InferredNames[E.Index],
- ))
- }
- } else {
- ctx.Inferred[E.Index] = expr.Type
- return expr, nil
- }
- }
- case NamedType:
- switch T := expr.Type.(type) {
- case NamedType:
- if E.Name == T.Name && ctx.InferTypeArgs {
- var err = compare_named(E, T)
- if err != nil {
- return Expr{}, err
- } else {
- return expr, nil
- }
- } else {
- var g = ctx.ModuleInfo.Types[E.Name]
- var union, is_union = g.Value.(Union)
- if is_union {
- return assign_union(E, T, union)
- } else {
- // "fallthrough" to strict equal or unbox
- }
- }
- }
- }
- if AreTypesEqualInSameCtx(expected, expr.Type) {
- return expr, nil
- } else {
- if unbox {
- var unboxed, ok = Unbox(expr.Type, ctx).(Unboxed)
- if ok {
- var expr_unboxed = Expr {
- Type: unboxed.Type,
- Value: expr.Value,
- Info: expr.Info,
- }
- var expr_expected, err = AssignTypedTo (
- expected, expr_unboxed, ctx, false,
- )
- // if err != nil { return Expr{}, err }
- if err != nil { return Expr{}, throw("") }
- if ctx.UnboxCounted {
- *(ctx.UnboxCount) += 1
- }
- return expr_expected, nil
- }
- }
- return Expr{}, throw("")
- }
- }
- }
|