mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-18 10:53:40 +00:00
If we want to encourage people to read the sample programs
and learn Mercury programming from them, they should not be written
in an obsolete style.
samples/beer.m:
samples/calculator.m:
samples/calculator2.m:
samples/concurrency/midimon/midimon.m:
samples/diff/diff_out.m:
samples/e.m:
samples/eliza.m:
samples/muz/dict.m:
samples/muz/higher_order.m:
samples/muz/muz.m:
samples/muz/typecheck.m:
samples/muz/word.m:
samples/muz/zabstract.m:
samples/muz/zlogic.m:
samples/muz/zparser.m:
samples/muz/ztoken.m:
samples/muz/ztoken_io.m:
samples/muz/ztype.m:
samples/muz/ztype_op.m:
samples/rot13/rot13_concise.m:
samples/rot13/rot13_gustavo.m:
samples/rot13/rot13_juergen.m:
samples/rot13/rot13_ralph.m:
samples/rot13/rot13_verbose.m:
samples/solutions/all_solutions.m:
samples/solutions/n_solutions.m:
samples/solutions/one_solution.m:
samples/solutions/some_solutions.m:
samples/solver_types/eqneq.m:
samples/solver_types/sudoku.m:
samples/solver_types/test_eqneq.m:
Replace uses of __ as module qualifier with dot.
Replace (C->T;E) with (if C then T else E).
Use our usual indentation for if-then-elses and for switches.
Import one module per line. Put those imports into alphabetical order.
Replace many uses of DCGs with state variables, leaving DCGs
mostly just for parsing code.
Use predmode declarations where this helps.
Put predicates in top-down order where relevant.
Use io.format where this helps.
Do not put more than one predicate call on one line.
Put each function symbol in a du type on a separate line.
Put spaces after commas, around the bar in list syntax,
around arithmetic operators, and around minus signs used for pairs.
Replace tab indentation with four-space indentation.
Delete spaces at the ends of lines.
Replace two or more consecutive blank lines with one blank line.
Delete blank lines that do not help structure the code.
There are probably still some examples of old practices remaining;
I do not claim to have fixed them all.
807 lines
25 KiB
Mathematica
807 lines
25 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1995-1999, 2006 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% file: typecheck.m
|
|
% main author: philip
|
|
|
|
:- module typecheck.
|
|
|
|
:- interface.
|
|
|
|
:- import_module dict.
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module word.
|
|
:- import_module zabstract.
|
|
:- import_module ztype.
|
|
|
|
% :- type typed_par == triple(par, subst, ptypes).
|
|
|
|
:- type type_result
|
|
---> yes(list(triple(par, subst, ptypes)))
|
|
; no.
|
|
|
|
:- pred zcheck(flags::in, list(par)::in, type_result::out,
|
|
dict::in, dict::out, io::di, io::uo) is det.
|
|
|
|
:- implementation.
|
|
|
|
:- import_module higher_order.
|
|
:- import_module int.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
:- import_module ztype_op.
|
|
|
|
:- type cstate
|
|
---> c(io, status, dict, ptypes, subst, flags).
|
|
|
|
zcheck(F, Spec, Result, D0, D, IO0, IO) :-
|
|
zcheck(Spec, TypedSpec,
|
|
c(IO0, ok, D0, initPtypes, initSubst, F),
|
|
c(IO1, S, D , _, _, _F)),
|
|
unsafe_promise_unique(IO1, IO),
|
|
( S = ok, Result = yes(TypedSpec)
|
|
; S = error, Result = no
|
|
).
|
|
|
|
:- pred zcheck(list(par), list(triple(par, subst, ptypes)), cstate, cstate).
|
|
:- mode zcheck(in, out, in, out) is det.
|
|
|
|
zcheck(Spec, TypedSpec) -->
|
|
( if tdebugging then
|
|
tout(["Starting type checking ...\n"])
|
|
else
|
|
{true}
|
|
),
|
|
list.map_foldl(par_check0, Spec, TypedSpec),
|
|
( if tdebugging then
|
|
tout(["... Finished type checking.\n"])
|
|
else
|
|
{true}
|
|
).
|
|
|
|
:- pred operators(operators::out, cstate::in, cstate::out) is det.
|
|
operators(operators(F), C, C) :-
|
|
C = c(_, _, _, _, _, F).
|
|
|
|
:- pred abbreviations(abbreviations::out, cstate::in, cstate::out) is det.
|
|
abbreviations(abbreviations(F), C, C) :-
|
|
C = c(_, _, _, _, _, F).
|
|
|
|
:- pred monotonics(monotonics::out, cstate::in, cstate::out) is det.
|
|
monotonics(monotonics(F), C, C) :-
|
|
C = c(_, _, _, _, _, F).
|
|
|
|
:- pred tdebugging(cstate::in, cstate::out) is semidet.
|
|
tdebugging(C, C) :-
|
|
C = c(_, _, _, _, _, F), debugging(F).
|
|
|
|
:- pred getDict(dict::out, cstate::in, cstate::out) is det.
|
|
getDict(D, C, C) :-
|
|
C = c(_, _, D, _, _, _).
|
|
|
|
:- pred putDict(dict::in, cstate::in, cstate::out) is det.
|
|
putDict(D, c(IO, S, _, G, Sub, F), c(IO, S, D, G, Sub, F)).
|
|
|
|
:- pred getPtypes(ptypes::out, cstate::in, cstate::out) is det.
|
|
getPtypes(P, C, C) :-
|
|
C = c(_, _, _, P, _, _).
|
|
|
|
:- pred putPtypes(ptypes::in, cstate::in, cstate::out) is det.
|
|
putPtypes(P, c(IO, S, D, _, Sub, F), c(IO, S, D, P, Sub, F)).
|
|
|
|
:- pred getSubst(subst::out, cstate::in, cstate::out) is det.
|
|
getSubst(S, C, C) :- C = c(_, _, _, _, S, _).
|
|
|
|
:- pred putSubst(subst::in, cstate::in, cstate::out) is det.
|
|
putSubst(Sub, c(IO, S, D, P, _, F), c(IO, S, D, P, Sub, F)).
|
|
|
|
:- pred substEnv(pred(Type, Result, subst, subst), Type, Result,
|
|
cstate, cstate).
|
|
:- mode substEnv(pred(out, out, in, out) is det, out, out, in, out) is det.
|
|
substEnv(P, T, R) -->
|
|
getSubst(S0),
|
|
{P(T, R, S0, S)},
|
|
putSubst(S).
|
|
|
|
:- pred add_sexpr_type(ref::in, slist::in, cstate::in, cstate::out) is det.
|
|
add_sexpr_type(Ref, DL, c(IO, S, D, PM0, Sub, F), c(IO, S, D, PM, Sub, F)) :-
|
|
ztype.add_sexpr_type(Ref, DL, PM0, PM).
|
|
|
|
:- pred tout(list(string), cstate, cstate).
|
|
:- mode tout(in, in, out /*cstate*/) is det.
|
|
tout(ML, c(IO0, S, D, G, Sub, F), c(IO, S, D, G, Sub, F)) :-
|
|
unsafe_promise_unique(IO0, IO1),
|
|
io.write_strings(ML, IO1, IO).
|
|
|
|
:- type terror_poly_type
|
|
---> s(string)
|
|
; t(ztype)
|
|
; e(expr)
|
|
; d(ident)
|
|
; i(int).
|
|
|
|
:- type telist == list(terror_poly_type).
|
|
|
|
:- pred te_To_String(operators, terror_poly_type, string).
|
|
:- mode te_To_String(in, in, out) is det.
|
|
|
|
te_To_String(_, s(S), S).
|
|
te_To_String(O, t(T), ztypePortray(O, T)).
|
|
te_To_String(O, e(E), exprPortray(O, E)).
|
|
te_To_String(_, d(I), identPortray(I)).
|
|
te_To_String(_, i(I), S) :-
|
|
string.int_to_string(I, S).
|
|
|
|
:- pred terror(int, telist, cstate, cstate).
|
|
:- mode terror(in, in, in, out /*cstate*/) is det.
|
|
terror(LN, TL, c(IO0, _, D, G, Sub, F), c(IO, error, D, G, Sub, F)) :-
|
|
string.int_to_string(LN, LNS),
|
|
list.map(te_To_String(operators(F)), TL, ML),
|
|
list.append(ML, [".\n"], ML1),
|
|
unsafe_promise_unique(IO0, IO1),
|
|
terror1(LNS, ML1, IO1, IO).
|
|
|
|
:- pred terror1(string::in, list(string)::in, io::di, io::uo) is det.
|
|
|
|
terror1(LNS, ML1) -->
|
|
unsafe_promise_unique,
|
|
io.input_stream_name(N),
|
|
io.stderr_stream(StdErr),
|
|
io.write_strings(StdErr, [N, ":", LNS, ": " | ML1]).
|
|
|
|
:- pred mismatch3(zcontext, list(mismatch3), cstate, cstate).
|
|
:- mode mismatch3(in, in, in, out /*cstate*/) is det.
|
|
|
|
mismatch3(_, []) --> [].
|
|
mismatch3(C, [mismatch(I, XT, YT) | ML]) -->
|
|
terror(C,
|
|
[s("Type mismatch in declarations of "),
|
|
d(I), s("--\n\t"),
|
|
t(XT), s(", "), t(YT)]),
|
|
mismatch3(C, ML).
|
|
|
|
:- pred addgD(zcontext, ident, entry, cstate, cstate).
|
|
:- mode addgD(in, in, in, in, out /*cstate*/) is det.
|
|
|
|
addgD(C, I, N0) -->
|
|
abbreviations(A),
|
|
{ if list.member(I, A) then
|
|
N0 = e(F, T0),
|
|
T = powerT(abbreviationT(I, T0, F)),
|
|
N = e(F, T)
|
|
else
|
|
N = N0
|
|
},
|
|
getDict(D0),
|
|
( if {dict.insert(I, N, D0, D)} then
|
|
putDict(D),
|
|
{N = e(FD, TD)}, debugDict("<--- ", I, FD, TD)
|
|
else
|
|
terror(C, [
|
|
s("Global identifier "), d(I), s(" already declared")])
|
|
).
|
|
|
|
:- pred lookupD(zcontext, ident, ztarity, ztype, cstate, cstate).
|
|
:- mode lookupD(in, in, out, out, in, out /*cstate*/) is det.
|
|
lookupD(C, I, F, T) -->
|
|
getDict(D),
|
|
( if {dict.search(I, e(F0, T0), D)} then
|
|
{F = F0, T = T0}
|
|
else
|
|
terror(C, [s("Identifier "), d(I), s(" is not declared")]),
|
|
{F = 0, T = unityT}
|
|
),
|
|
debugDict("---> ", I, F, T).
|
|
|
|
:- pred debugDict(string, ident, ztarity, ztype, cstate, cstate).
|
|
:- mode debugDict(in, in, in, in, in, out) is det.
|
|
|
|
debugDict(S, I, F, T) -->
|
|
( if tdebugging then
|
|
operators(O), {DS = declPortray(O, I - T)},
|
|
( if {F = 0} then
|
|
tout([S, DS, "\n"])
|
|
else
|
|
{string.int_to_string(F, FS)},
|
|
tout([S, "[", FS, "]:", DS, "\n"])
|
|
)
|
|
else
|
|
{true}
|
|
).
|
|
|
|
:- pred actuals_check(maybe(list(expr)), maybe(list(ztype)), cstate, cstate).
|
|
:- mode actuals_check(in, out, in, out /*cstate*/) is det.
|
|
|
|
actuals_check(no, no) --> [].
|
|
actuals_check(yes(A0), yes(AT)) -->
|
|
list.map_foldl(set_check("Actual generic parameter"), A0, AT).
|
|
|
|
:- pred actualiseResult(zcontext, ident, actualisationResult, cstate, cstate).
|
|
:- mode actualiseResult(in, in, in, in, out /*cstate*/) is det.
|
|
|
|
actualiseResult(_, _, ok) --> [].
|
|
actualiseResult(C, I, arityError(F, AN)) -->
|
|
terror(C,
|
|
[s("Identifier "), d(I), s(" has "),
|
|
i(F), s(" formals but "), i(AN),s(" actuals")]).
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% :- type global ---> global(zcontext, ident, ztype).
|
|
|
|
:- pred par_check0(par, triple(par, subst, ptypes), cstate, cstate).
|
|
:- mode par_check0(in, out, in, out /*cstate*/) is det.
|
|
|
|
par_check0(Par, triple(Par, S, P)) -->
|
|
{Par = Par1 - C},
|
|
par_check(C, Par1, F, LG0),
|
|
getSubst(S0),
|
|
{incompletelyDetermined(EL, S0, S)},
|
|
% psubst(S),
|
|
getPtypes(P),
|
|
% For VarSource type see below or in ztype.m ---
|
|
% should use this to improve error messages!
|
|
{P0 =
|
|
( pred(unbound(Expr, _VarSource)::in, in, out) is det -->
|
|
{Expr = _ - VC},
|
|
terror(VC, [
|
|
s("Implicit type parameter not determined--"),
|
|
s("\n\tExpression: "), e(Expr)
|
|
])
|
|
)},
|
|
list.foldl(P0, EL),
|
|
{ if F = [] then
|
|
P1 =
|
|
( pred(I - T::in, U::out) is det :-
|
|
U = I - e(0, ztapply(S, T))
|
|
),
|
|
list.map(P1, LG0, LG)
|
|
else
|
|
makeGeneric(S, F, LG0, LG)
|
|
},
|
|
{P2 = (pred(I - E::in, in, out) is det --> addgD(C, I, E))},
|
|
list.foldl(P2, LG),
|
|
putPtypes(initPtypes),
|
|
putSubst(initSubst).
|
|
|
|
%:- type varsource
|
|
%---> parameter(ref, int) ; function_arg ; function_result ; power ; extension.
|
|
|
|
:- pred psubst(subst::in, cstate::in, cstate::out) is det.
|
|
psubst(Sub, c(IO0, E, D, G, S, F), c(IO, E, D, G, S, F)) :-
|
|
unsafe_promise_unique(IO0, IO1),
|
|
Sub = Sub1 - V,
|
|
map.to_assoc_list(Sub1, AL),
|
|
io.write(AL - V, IO1, IO2),
|
|
io.nl(IO2, IO).
|
|
|
|
:- pred par_check(zcontext, par1, formals, slist, cstate, cstate).
|
|
:- mode par_check(in, in, out, out, in, out /*cstate*/) is det.
|
|
par_check(_C, given(L), [], LG) -->
|
|
{P = (pred(I::in, I - givenType(I)::out) is det),
|
|
list.map(P, L, LG)}.
|
|
%par_check(C, let(S) - C) --> resetGen, sexpr_check(C, S, _T).
|
|
par_check(_C, sdef(I, F, SExpr), F, [I - powerT(schemaT(T))]) -->
|
|
getDict(D),
|
|
installFormals(F),
|
|
sexpr_check(SExpr, T),
|
|
putDict(D).
|
|
par_check(_C, eqeq(I, F, X), F, [I - T]) -->
|
|
getDict(D),
|
|
installFormals(F),
|
|
expr_check(X, T),
|
|
putDict(D).
|
|
par_check(C, data(Ref, I, L), [], LG) -->
|
|
addgD(C, I, e(0, givenType(I))), % I may be referred to in the branches
|
|
list.map_foldl(branch_check(I), L, LG),
|
|
add_sexpr_type(Ref, LG).
|
|
par_check(_C, zpred(P), [], []) -->
|
|
zpred_check(P).
|
|
par_check(_C, define(F, SExpr), F, LG) -->
|
|
getDict(D),
|
|
installFormals(F),
|
|
sexpr_check(SExpr, LG),
|
|
putDict(D).
|
|
|
|
:- pred installFormals(list(ident)::in, cstate::in, cstate::out) is det.
|
|
installFormals([]) --> []. % This clause avoids trace
|
|
installFormals(F) -->
|
|
{F = [_ | _]},
|
|
{Function = (pred(I::in, I - powerT(parameterT(I))::out) is det)},
|
|
{list.map(Function, F, DL)},
|
|
install_dlist(DL).
|
|
|
|
:- pred branch_check(ident, branch, pair(ident, ztype), cstate, cstate).
|
|
:- mode branch_check(in, in, out, in, out /*cstate*/) is det.
|
|
branch_check(Id, branch(Ref, I, M), I - T) -->
|
|
(
|
|
{M = yes(X),
|
|
% T should be T0 \pfun givenT(Id) to make use of abbreviations
|
|
Args = [T0, givenT(Id)],
|
|
F = ((func) = powerT(cproductT(Args)))},
|
|
set_check("Branch expression", X, T0),
|
|
try_abbrev_type(X, Ref, "\\pfun", F, Args, T)
|
|
;
|
|
{M = no,
|
|
T = givenT(Id)}
|
|
).
|
|
|
|
:- pred sexpr_checkCT(sexpr, ztype, cstate, cstate).
|
|
:- mode sexpr_checkCT(in, out, in, out /*cstate*/) is det.
|
|
sexpr_checkCT(sexpr(Ref, SExpr, C), T) -->
|
|
( if {SExpr = text(L0, PL)} then
|
|
declL_checkCT(C, L0, DL, TL),
|
|
install_dlist(DL),
|
|
list.foldl(zpred_check, PL),
|
|
{(if TL = [T0] then T = T0 else T = cproductT(TL))}
|
|
else
|
|
sexpr_check(Ref, C, SExpr, DL),
|
|
install_dlist(DL),
|
|
{T = schemaT(DL)}
|
|
),
|
|
add_sexpr_type(Ref, DL).
|
|
|
|
:- pred declL_checkCT(zcontext, list(decl), slist, list(ztype), cstate, cstate).
|
|
:- mode declL_checkCT(in, in, out, out, in, out /*cstate*/) is det.
|
|
declL_checkCT(_, [], [], []) -->
|
|
[].
|
|
declL_checkCT(C, [H | L], DTL, TTL) -->
|
|
decl_checkCT(H, DT, TT),
|
|
declL_checkCT(C, L, DTL0, TTL0),
|
|
substEnv(slist_merge(DT, DTL0), DTL, ML), mismatch3(C, ML),
|
|
{list.append(TT, TTL0, TTL)}.
|
|
|
|
:- pred decl_checkCT(decl, slist, list(ztype), cstate, cstate).
|
|
:- mode decl_checkCT(in, out, out, in, out /*cstate*/) is det.
|
|
decl_checkCT(decl(L0, X), L, TL) -->
|
|
set_check("Declaration expression", X, T),
|
|
{list.sort(L0, L1),
|
|
list.remove_adjacent_dups(L1, L2),
|
|
list.map(
|
|
( pred(I::in, O::out) is det :-
|
|
O = I - T
|
|
), L2, L)},
|
|
{list.length(L0, N),
|
|
list.duplicate(N, T, TL)}.
|
|
decl_checkCT(include(S), T, [schemaT(T)]) -->
|
|
sexpr_check(S, T).
|
|
|
|
:- pred set_check(string, expr, ztype, cstate, cstate).
|
|
:- mode set_check(in, in, out, in, out /*cstate*/) is det.
|
|
set_check(Str, X, T) -->
|
|
expr_check(X, T0),
|
|
substEnv(powerType(X, T0), T, M),
|
|
(
|
|
{M = yes}
|
|
;
|
|
{M = no(ET)},
|
|
{X = _ - C},
|
|
terror(C, [
|
|
s(Str), s(" must be set-valued---"),
|
|
s("\n\tExpression: "), e(X),
|
|
s("\n\tType: "), t(ET)
|
|
])
|
|
).
|
|
|
|
:- pred zpred_check(zpred, cstate, cstate).
|
|
:- mode zpred_check(in, in, out /*cstate*/) is det.
|
|
|
|
zpred_check(equality(X0, X1) - C) -->
|
|
expr_check(X0, T0), expr_check(X1, T1),
|
|
{O = " = "},
|
|
substEnv(ztunify(T0, T1), _, U),
|
|
(
|
|
{U = unified}
|
|
;
|
|
{U = failed(FS)},
|
|
terror(C, [
|
|
s("Type mismatch in equation--"),
|
|
s("\n\tEquation: "), e(X0), s(O), e(X1),
|
|
s("\n\tTypes: "),
|
|
t(ztapply(FS, T0)), s(O), t(ztapply(FS, T1))
|
|
])
|
|
).
|
|
zpred_check(membership(X0, X1) - C) -->
|
|
expr_check(X0, T0), set_check("Relation or 2nd arg to \\in", X1, T1),
|
|
{O = " \\in "},
|
|
substEnv(ztunify(T0, T1), _, U),
|
|
(
|
|
{U = unified}
|
|
;
|
|
{U = failed(FS)},
|
|
terror(C, [
|
|
s("Type mismatch in predicate--"),
|
|
s("\n\tPredicate: "), e(X0), s(O), e(X1),
|
|
s("\n\tTypes: "), t(ztapply(FS, T0)), s(O),
|
|
t(ztapply(FS, powerT(T1)))
|
|
])
|
|
).
|
|
zpred_check(truth - _) --> [].
|
|
zpred_check(falsehood - _) --> [].
|
|
zpred_check(negation(P) - _) --> zpred_check(P).
|
|
zpred_check(lbpred(_, P0, P1) - _) --> zpred_check(P0), zpred_check(P1).
|
|
zpred_check(quantification(_, S, P) - _) -->
|
|
sexpr_check(S, SList),
|
|
getDict(D),
|
|
install_dlist(SList),
|
|
zpred_check(P),
|
|
putDict(D).
|
|
zpred_check(sexpr(S) - C) -->
|
|
% ***BUG
|
|
% Need to check that SList is already defined and in the environment
|
|
sexpr_check(S, SList),
|
|
check_slist_defined(C, SList).
|
|
zpred_check(let(L, P) - C) -->
|
|
getDict(D),
|
|
assoc_list_ident_expr_check(L, SL0),
|
|
substEnv(slist_sort(SL0), SL, ML), mismatch3(C, ML),
|
|
install_dlist(SL),
|
|
zpred_check(P),
|
|
putDict(D).
|
|
|
|
:- pred check_slist_defined(zcontext, slist, cstate, cstate).
|
|
:- mode check_slist_defined(in, in, in, out /*cstate*/) is det.
|
|
check_slist_defined(C, SList) -->
|
|
{P =
|
|
( pred(I - _::in, I - T::out, in, out) is det -->
|
|
lookupD(C, I, _, T)
|
|
)},
|
|
list.map_foldl(P, SList, EnvList),
|
|
substEnv(slist_merge(SList, EnvList), _Type, ML), mismatch3(C, ML).
|
|
|
|
%%%
|
|
% 5 EXPRESSION
|
|
|
|
:- pred expr_check(expr, ztype, cstate, cstate).
|
|
:- mode expr_check(in, out, in, out /*cstate*/) is det.
|
|
% 5.2 Identifier
|
|
% 5.3 Generic Instantiation
|
|
expr_check(Expr, T) -->
|
|
{Expr = ref(Ref, I, MActuals) - C},
|
|
lookupD(C, I, F, T0),
|
|
actuals_check(MActuals, MActualTypes),
|
|
substEnv(actualise(Expr, Ref, F, T0, MActualTypes), T, Result),
|
|
actualiseResult(C, I, Result).
|
|
|
|
% 5.4 Number Literal
|
|
expr_check(number(_) - _, numType) --> [].
|
|
% 5.5 String Literal
|
|
expr_check(stringl(_) - _, stringType) --> [].
|
|
% 5.6 Set Extension
|
|
expr_check(X, T) -->
|
|
{X = display(Ref, D, L) - C},
|
|
list.map_foldl(expr_check, L, TL),
|
|
substEnv(check_sameL(X, TL), T0, M),
|
|
(
|
|
{D = set, T = powerT(T0)}
|
|
;
|
|
{D = seq},
|
|
{F = ((func) = powerT(cproductT([numType, T0])))},
|
|
try_abbrev_type(X, Ref, "\\seq", F, [T0], T)
|
|
;
|
|
{D = bag},
|
|
{F = ((func) = powerT(cproductT([T0, numType])))},
|
|
try_abbrev_type(X, Ref, "\\bag", F, [T0], T)
|
|
),
|
|
(
|
|
{M = no}
|
|
;
|
|
{M = yes(mismatch(T1, T2))},
|
|
terror(C, [
|
|
s("Type mismatch in elements of "),
|
|
s(display_to_string(D)), s("--"),
|
|
s("\n\tExpression: "), e(X),
|
|
s("\n\tTypes: "), t(T1), s(", "), t(T2)])
|
|
).
|
|
|
|
% 5.7 Set Comprehension
|
|
expr_check(setcomp(S, M) - _, powerT(T)) -->
|
|
getDict(D),
|
|
sexpr_checkCT(S, T0),
|
|
( {M = yes(X)}, expr_check(X, T)
|
|
; {M = no, T = T0}
|
|
),
|
|
putDict(D).
|
|
expr_check(lambda(S, X) - _, powerT(cproductT([T0, T1]))) -->
|
|
getDict(D),
|
|
sexpr_checkCT(S, T0),
|
|
expr_check(X, T1),
|
|
putDict(D).
|
|
% 5.8 Power Set (see 5.3)
|
|
expr_check(powerset(X) - _, powerT(T)) -->
|
|
expr_check(X, T).
|
|
% 5.9 Tuple
|
|
expr_check(tuple(L) - _, cproductT(TL)) -->
|
|
list.map_foldl(expr_check, L, TL).
|
|
% 5.10 Cartesian Product
|
|
expr_check(product(L) - _, powerT(cproductT(TL))) -->
|
|
list.map_foldl(set_check("Cross - product argument"), L, TL).
|
|
% 5.11 Tuple Selection
|
|
expr_check(X, T) -->
|
|
{X = tupleselection(X0, SelStr) - C},
|
|
expr_check(X0, T0),
|
|
{ if string.to_int(SelStr, N0) then
|
|
N = N0
|
|
else
|
|
error("expr_check/2: string.to_int failed")
|
|
},
|
|
substEnv(tupleSelect(N, T0), T, M),
|
|
(
|
|
{M = yes}
|
|
;
|
|
{M = outsideArity(ET)},
|
|
terror(C, [
|
|
s("Tuple selection outside 1..arity--"),
|
|
s("\n\tExpression: "), e(X),
|
|
s("\n\tTuple type: "), t(ET)
|
|
])
|
|
;
|
|
{M = nontuple(ET)},
|
|
terror(C, [
|
|
s("Tuple selection from non-tuple--"),
|
|
s("\n\tExpression: "), e(X),
|
|
s("\n\tNon-tuple type: "), t(ET)
|
|
])
|
|
).
|
|
% 5.12 Binding Extension
|
|
% (not yet implemented)
|
|
expr_check(let(L, X) - C, T) -->
|
|
getDict(D),
|
|
assoc_list_ident_expr_check(L, SL0),
|
|
substEnv(slist_sort(SL0), SL, ML),
|
|
mismatch3(C, ML),
|
|
install_dlist(SL),
|
|
expr_check(X, T),
|
|
putDict(D).
|
|
% 5.13 Theta Expression
|
|
expr_check(X, schemaT(DL)) -->
|
|
{X = theta(Ref, S, D) - C},
|
|
sexpr_check(S, DL0),
|
|
{decorate(D, DL0, DL1)},
|
|
theta_check(C, DL0, DL1, DL),
|
|
add_sexpr_type(Ref, DL).
|
|
% 5.14 Schema Expression
|
|
expr_check(sexp(S) - _, powerT(schemaT(T))) --> sexpr_check(S, T).
|
|
% 5.15 Binding Selection
|
|
expr_check(X, T) -->
|
|
{X = select(Ref, X0, I) - C},
|
|
expr_check(X0, T0),
|
|
substEnv(bindingSelect(I, T0), T, M),
|
|
(
|
|
{M = yes(DL)}
|
|
;
|
|
{M = nonexistent(ET), DL = []},
|
|
terror(C, [
|
|
s("Selection of non-existent component--"),
|
|
s("\n\tExpression: "), e(X),
|
|
s("\n\tSchema type: "), t(ET)
|
|
])
|
|
;
|
|
{M = nonbinding(ET), DL = []},
|
|
terror(C, [
|
|
s("Selection from non-schema--"),
|
|
s("\n\tExpression: "), e(X),
|
|
s("\n\tNon-schema type: "), t(ET)
|
|
])
|
|
),
|
|
add_sexpr_type(Ref, DL).
|
|
% 5.16 Function Application
|
|
expr_check(X, ResultT) -->
|
|
{X = zapply(_Ref, Function, Actual) - C},
|
|
expr_check(Function, FunctionT), expr_check(Actual, ActualT),
|
|
% If FunctionT has generic parameters and
|
|
% not (Function is an ident and the ident is tame)
|
|
% then generate conservative types in the application
|
|
( if
|
|
{Function = ref(_, I, _) - _},
|
|
monotonics(MF),
|
|
{list.member(I, MF)}
|
|
then
|
|
{Flag = is_monotonic}
|
|
else
|
|
{Flag = is_unknown}
|
|
),
|
|
substEnv(applyTypes(Flag, Function, X, FunctionT, ActualT), ResultT, M),
|
|
(
|
|
{M = yes}
|
|
;
|
|
{M = nonfunction(FunctionE)},
|
|
terror(C, [
|
|
s("Application of non-function--"),
|
|
s("\n\tExpression: "), e(X),
|
|
s("\n\tNon-function type: "), t(FunctionE)
|
|
])
|
|
;
|
|
{M = mismatch(FormalE, ActualE)},
|
|
terror(C, [
|
|
s("Type mismatch in function application--"),
|
|
s("\n\tExpression: "), e(X),
|
|
s("\n\tExpected: "), t(FormalE),
|
|
s("\n\tFound: "), t(ActualE)
|
|
])
|
|
).
|
|
% 5.17 Definite Description
|
|
expr_check(mu(S, M) - _, T) -->
|
|
getDict(D),
|
|
sexpr_checkCT(S, T0),
|
|
( {M = yes(X)}, expr_check(X, T)
|
|
; {M = no, T = T0}
|
|
),
|
|
putDict(D).
|
|
% 5.18 Conditional Expression
|
|
expr_check(if(P, X0, X1) - C, T) -->
|
|
zpred_check(P), expr_check(X0, T0), expr_check(X1, T1),
|
|
substEnv(ztunify(T0, T1), T, U),
|
|
(
|
|
{U = unified}
|
|
;
|
|
{U = failed(FS)},
|
|
terror(C, [s("Type mismatch in conditional expression--"),
|
|
s("\n\tExpression: if ... then "), e(X0), s(" else "), e(X1),
|
|
s("\n\tTypes: if ... then "), t(ztapply(FS, T0)),
|
|
s(" else "), t(ztapply(FS, T1))
|
|
])
|
|
).
|
|
% 5.19 Substitution
|
|
% (not yet implemented)
|
|
|
|
:- pred try_abbrev_type(expr, ref, word, (func) = ztype, list(ztype), ztype,
|
|
cstate, cstate).
|
|
:- mode try_abbrev_type(in, in, in, (func) = out is det, in, out, in, out)
|
|
is det.
|
|
|
|
try_abbrev_type(Expr, Ref, Name, F, ActualTypes, T) -->
|
|
getDict(Dict),
|
|
{list.length(ActualTypes, Length)},
|
|
( if
|
|
{dict.search(id(no, Name, []), e(Length, Type0), Dict),
|
|
powerType(Type0, Type1, yes)}
|
|
then
|
|
substEnv(actualise(Expr, Ref, Length, Type1, yes(ActualTypes)), T, _)
|
|
else
|
|
{T = apply(F)}
|
|
).
|
|
|
|
:- pred theta_check(zcontext, slist, slist, slist, cstate, cstate).
|
|
:- mode theta_check(in, in, in, out, in, out /*cstate*/) is det.
|
|
|
|
theta_check(_, [], [], []) --> [].
|
|
theta_check(_, [_|_], [], _) -->
|
|
{error("theta_check/6: length mismatch")}.
|
|
theta_check(_, [], [_|_], _) -->
|
|
{error("theta_check/6: length mismatch")}.
|
|
theta_check(C, [I0 - SchemaType | T0], [I1 - _SType | T1], [I0 - Type | T]) -->
|
|
% assert(SchemaType = _SType)
|
|
lookupD(C, I1, _F, EnvType),
|
|
substEnv(ztunify(SchemaType, EnvType), Type, U),
|
|
(
|
|
{U = unified} % BUG: should check that Type is ground
|
|
;
|
|
{U = failed(FS)},
|
|
terror(C, [s("Type mismatch in theta expression--"),
|
|
s("\n\tIdentifiers (theta::env): "), d(I0), s("::"), d(I1),
|
|
s("\n\tTypes: (theta/env) "), t(ztapply(FS, SchemaType)),
|
|
s("::"), t(ztapply(FS, EnvType))
|
|
])
|
|
),
|
|
theta_check(C, T0, T1, T).
|
|
|
|
%%%
|
|
|
|
:- pred sexpr_check(sexpr, slist, cstate, cstate).
|
|
:- mode sexpr_check(in, out, in, out /*cstate*/) is det.
|
|
|
|
sexpr_check(sexpr(Ref, S, C), TL) -->
|
|
sexpr_check(C, Ref, S, TL),
|
|
add_sexpr_type(Ref, TL).
|
|
|
|
:- pred sexpr_check(zcontext, ref, sexpr1, slist, cstate, cstate).
|
|
:- mode sexpr_check(in, in, in, out, in, out /*cstate*/) is det.
|
|
|
|
sexpr_check(C, Ref, SRef, DL) -->
|
|
{SRef = ref(I, MActual)},
|
|
lookupD(C, I, F, T0),
|
|
actuals_check(MActual, MActualTypes),
|
|
{Expr = sexp(sexpr(Ref, SRef, C)) - C},
|
|
substEnv(actualise(Expr, Ref, F, T0, MActualTypes), T, Result),
|
|
actualiseResult(C, I, Result),
|
|
( if {powerType(T, TS, yes), schemaType(TS, DL0)} then
|
|
{DL = DL0}
|
|
else
|
|
{DL = []},
|
|
terror(C,
|
|
[s("Identifier "), d(I),
|
|
s(" expected to be a schema name")])
|
|
).
|
|
sexpr_check(C, _, text(DL, PL), SL) -->
|
|
declL_checkCT(C, DL, SL, _TL),
|
|
install_dlist(SL),
|
|
list.foldl(zpred_check, PL).
|
|
sexpr_check(_, _, negation(X), T) -->
|
|
sexpr_check(X, T).
|
|
sexpr_check(C, _, lbpred(_, X0, X1), T) -->
|
|
sexpr_check(X0, T1), sexpr_check(X1, T2),
|
|
substEnv(slist_merge(T1, T2), T, ML), mismatch3(C, ML).
|
|
sexpr_check(C, _, projection(Ref, X0, X1), T) -->
|
|
sexpr_check(X0, T0), sexpr_check(X1, T1),
|
|
getSubst(S0),
|
|
{slist_project(T0, T1, T, ET, ML, S0, S)},
|
|
putSubst(S),
|
|
mismatch3(C, ML),
|
|
add_sexpr_type(Ref, ET).
|
|
sexpr_check(_, _, hide(Ref, X, L), T) -->
|
|
sexpr_check(X, T0),
|
|
{list.sort_and_remove_dups(L, L1)},
|
|
{slist_hide(T0, L1, T, T1)},
|
|
add_sexpr_type(Ref, T1).
|
|
sexpr_check(C, _, quantification(_, SExpr, X), T) -->
|
|
sexpr_check(SExpr, T0),
|
|
getDict(D),
|
|
install_dlist(T0),
|
|
sexpr_check(X, T1),
|
|
putDict(D),
|
|
substEnv(slist_quantify(T1, T0), T, ML),
|
|
mismatch3(C, ML).
|
|
sexpr_check(C, _, renaming(X, R), DL) -->
|
|
sexpr_check(X, DL0),
|
|
substEnv(rename(R, DL0), DL, ML),
|
|
mismatch3(C, ML).
|
|
sexpr_check(C, _, bsexpr(Ref, SConn, X0, X1), T) -->
|
|
sexpr_check(X0, T0),
|
|
sexpr_check(X1, T1),
|
|
% split list eg. into single prime+others for composition
|
|
{P = (pred(I::in, O::out) is semidet :- slist_ident_comp(SConn, I, O))},
|
|
{list.filter_map(P, T0, Mid0, TL)},
|
|
substEnv(slist_sort(Mid0), Mid, ML1),
|
|
mismatch3(C, ML1),
|
|
substEnv(slist_merge(T1, Mid), TR, ML2),
|
|
mismatch3(C, ML2),
|
|
substEnv(slist_merge(TL, TR), T, ML3),
|
|
mismatch3(C, ML3),
|
|
add_sexpr_type(Ref, Mid).
|
|
sexpr_check(_, _, decoration(X, D), DL) -->
|
|
sexpr_check(X, DL0),
|
|
{decorate(D, DL0, DL)}.
|
|
sexpr_check(_, _, pre(Ref, X), T) -->
|
|
sexpr_check(X, T0),
|
|
{P =
|
|
( pred(id(no, _Id, [D | _]) - _::in) is semidet :-
|
|
(D = prime ; D = exclamation_mark)
|
|
)},
|
|
{list.filter(P, T0, T1, T)},
|
|
add_sexpr_type(Ref, T1).
|
|
|
|
:- pred assoc_list_ident_expr_check(list(pair(ident, expr))::in, slist::out,
|
|
cstate::in, cstate::out) is det.
|
|
|
|
assoc_list_ident_expr_check([], []) --> [].
|
|
assoc_list_ident_expr_check([I - X | L], [I - T | LT]) -->
|
|
expr_check(X, T),
|
|
assoc_list_ident_expr_check(L, LT).
|
|
|
|
% {P = (pred(I - X::in, I - T::out, in, out) is det --> expr_check(X, T))},
|
|
% list.map_foldl(P, L, LT)
|
|
|
|
:- pred install_dlist(slist, cstate, cstate).
|
|
:- mode install_dlist(in, in, out /*cstate*/) is det.
|
|
|
|
install_dlist(L) -->
|
|
( if tdebugging then
|
|
operators(O),
|
|
{IS = declPortray(O, id(no, "", []) - schemaT(L))},
|
|
tout(["<--- ", IS, "\n"])
|
|
else
|
|
{true}
|
|
),
|
|
{list.map(pred(I - T::in, I - e(0, T)::out) is det, L, L1)},
|
|
getDict(D0),
|
|
{dict.overlay(L1, D0, D)},
|
|
putDict(D).
|