123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- package checker
- import (
- "kumachan/interpreter/lang/ast"
- "kumachan/interpreter/lang/common/name"
- "kumachan/interpreter/lang/common/source"
- "kumachan/interpreter/compiler/checker/typsys"
- "kumachan/interpreter/compiler/checker/checked"
- )
- type DispatchMapping (map[ImplPair] *checked.DispatchTable)
- type ImplPair struct {
- ConcreteType *typsys.TypeDef
- InterfaceType *typsys.TypeDef
- }
- func generateDispatchMapping (
- types typeList,
- functions FunctionRegistry,
- ) (DispatchMapping, source.Errors) {
- var mapping = make(DispatchMapping)
- var errs source.Errors
- for _, def := range types {
- var _, is_interface = def.Content.(*typsys.Interface)
- if is_interface {
- continue
- }
- var con = def.TypeDef
- var err = (func() *source.Error {
- for _, impl := range con.Implements {
- var _, err = makeDispatchTable(functions, con, impl, mapping)
- if err != nil { return err }
- }
- return nil
- })()
- source.ErrorsJoin(&errs, err)
- }
- if errs != nil { return nil, errs }
- return mapping, nil
- }
- func makeDispatchTable (
- f_reg FunctionRegistry,
- con *typsys.TypeDef,
- impl *typsys.TypeDef,
- mapping DispatchMapping,
- ) (*checked.DispatchTable, *source.Error) {
- var _, con_invalid = con.Content.(*typsys.Interface)
- if con_invalid {
- panic("invalid argument")
- }
- var pair = ImplPair {
- ConcreteType: con,
- InterfaceType: impl,
- }
- var existing, exists = mapping[pair]
- if exists {
- // diamond situation
- return existing, nil
- }
- var con_t = defType(con)
- var fields = impl.Content.(*typsys.Interface).Methods.Fields
- var methods = make([] checked.Method, len(fields))
- for i, field := range fields {
- var method_name = field.Name
- var method_t = methodType(con, impl, field.Type)
- var method_full_name = name.Name {
- ModuleName: con.Name.ModuleName,
- ItemName: field.Name,
- }
- var detail = func() ImplError { return ImplError {
- Concrete: con.Name.String(),
- Interface: impl.Name.String(),
- Method: method_name,
- } }
- var m_group, func_exists = f_reg[method_full_name]
- var m_index, field_exists = (func() (*uint, bool) {
- var record, is_record = getBoxedRecord(con)
- if is_record {
- var index, exists = record.FieldIndexMap[method_name]
- return &index, exists
- } else {
- return nil, false
- }
- })()
- if func_exists && field_exists {
- return nil, source.MakeError(con.Location,
- E_ImplMethodAmbiguous {
- ImplError: detail(),
- })
- } else if !(func_exists) && field_exists {
- methods[i] = checked.MethodField { Index: *(m_index) }
- } else if func_exists && !(field_exists) {
- var method_f *Function = nil
- var found = false
- for _, f := range m_group {
- if f.AstNode.Kind != ast.FK_Method {
- continue
- }
- var implicit = f.Signature.ImplicitContext
- var params = f.Signature.TypeParameters
- var io = f.Signature.InputOutput
- if len(implicit.Fields) > 0 {
- panic("something went wrong")
- }
- var in = typsys.TypeOpParameterReplace (
- params, con.Parameters, io.Input,
- )
- var out = typsys.TypeOpParameterReplace (
- params, con.Parameters, io.Output,
- )
- var ok = typsys.TypeOpEqualTypeVec (
- [] typsys.Type { in, out },
- [] typsys.Type { con_t, method_t },
- )
- if ok {
- if found {
- return nil, source.MakeError(con.Location,
- E_ImplMethodDuplicateCompatible {
- ImplError: detail(),
- })
- }
- found = true
- method_f = f
- }
- }
- if !(found) {
- return nil, source.MakeError(con.Location,
- E_ImplMethodNoneCompatible {
- ImplError: detail(),
- })
- }
- methods[i] = checked.MethodFunction { Name: method_f.Name }
- } else {
- return nil, source.MakeError(con.Location,
- E_ImplMethodNoSuchFunctionOrField {
- ImplError: detail(),
- })
- }
- }
- var included = make([] *checked.DispatchTable, len(impl.Implements))
- for i, impl_impl := range impl.Implements {
- var table, err = makeDispatchTable(f_reg, con, impl_impl, mapping)
- if err != nil { return nil, err }
- included[i] = table
- }
- var table = &checked.DispatchTable {
- Methods: methods,
- Included: included,
- Concrete: con.Name,
- Interface: impl.Name,
- }
- mapping[pair] = table
- return table, nil
- }
- func getBoxedRecord(def *typsys.TypeDef) (typsys.Record, bool) {
- var box, is_box = def.Content.(*typsys.Box)
- if is_box {
- var record, is_record = getRecord(box.InnerType)
- return record, is_record
- } else {
- return typsys.Record {}, false
- }
- }
- func defType(def *typsys.TypeDef) typsys.Type {
- return &typsys.NestedType {
- Content: typsys.Ref {
- Def: def,
- Args: (func() ([] typsys.Type) {
- var args = make([] typsys.Type, len(def.Parameters))
- for i := range def.Parameters {
- var p = &(def.Parameters[i])
- args[i] = typsys.ParameterType { Parameter: p }
- }
- return args
- })(),
- },
- }
- }
- func methodType(con *typsys.TypeDef, impl *typsys.TypeDef, raw typsys.Type) typsys.Type {
- if len(con.Parameters) != len(impl.Parameters) {
- panic("something went wrong")
- }
- return typsys.TypeOpMap(raw, func(t typsys.Type) (typsys.Type, bool) {
- var p, is_parameter = t.(typsys.ParameterType)
- if is_parameter {
- for i := range impl.Parameters {
- var impl_p = &(impl.Parameters[i])
- if p.Parameter == impl_p {
- var con_p = &(con.Parameters[i])
- return typsys.ParameterType { Parameter: con_p }, true
- }
- }
- return nil, false
- } else {
- return nil, false
- }
- })
- }
- func getInterface(t typsys.Type) (*typsys.Interface, *typsys.TypeDef, ([] typsys.Type), bool) {
- var nested, is_nested = t.(*typsys.NestedType)
- if !(is_nested) { return nil, nil, nil, false }
- var ref, is_ref = nested.Content.(typsys.Ref)
- if !(is_ref) { return nil, nil, nil, false }
- var interface_, is_interface = ref.Def.Content.(*typsys.Interface)
- if !(is_interface) { return nil, nil, nil, false }
- return interface_, ref.Def, ref.Args, true
- }
- func unboxInterface(t typsys.Type, mod string) (*typsys.Interface, *typsys.TypeDef, ([] typsys.Type), bool) {
- var interface_, def, args, is_interface = getInterface(t)
- if is_interface {
- return interface_, def, args, true
- } else {
- var inner, _, exists = typsys.Unbox(t, mod)
- if exists {
- return unboxInterface(inner, mod)
- } else {
- return nil, nil, nil, false
- }
- }
- }
|