[m-rev.] for review: fix mantis bug #82
Peter Wang
novalazy at gmail.com
Wed Aug 27 11:49:57 AEST 2008
Branches: main
Fix Mantis bug #82.
The compiler was not writing some dummy types to the implementation sections of
interface files, specifically types with one constructor with one argument
which is itself a dummy type. An importing module would not agree with the
defining module about the signature of a procedure which had such argument
types.
compiler/modules.m:
Reimplement `constructor_list_represents_dummy_argument_type' to
also recognises no-tag dummy types.
compiler/prog_type.m:
Delete old `constructor_list_represents_dummy_argument_type'.
compiler/type_util.m:
Add a reminder to keep `check_dummy_type' synchronised with
`constructor_list_represents_dummy_argument_type'.
tests/hard_coded/Mmakefile:
tests/hard_coded/dummy_no_tag.exp:
tests/hard_coded/dummy_no_tag.m:
tests/hard_coded/dummy_no_tag_2.m:
Add test case.
diff --git a/compiler/modules.m b/compiler/modules.m
index af563aa..303b85b 100644
--- a/compiler/modules.m
+++ b/compiler/modules.m
@@ -677,12 +677,13 @@ strip_unnecessary_impl_defns(Items0, Items) :-
some [!IntTypesMap, !ImplTypesMap, !ImplItems] (
gather_type_defns(Items0, IntItems0, !:ImplItems,
!:IntTypesMap, !:ImplTypesMap),
+ BothTypesMap = multi_map.merge(!.IntTypesMap, !.ImplTypesMap),
% Work out which module imports in the implementation section of
% the interface are required by the definitions of equivalence
% types and dummy types in the implementation.
get_requirements_of_impl_exported_types(!.IntTypesMap, !.ImplTypesMap,
- NecessaryDummyTypeCtors, NecessaryEqvTypeCtors,
+ BothTypesMap, NecessaryDummyTypeCtors, NecessaryEqvTypeCtors,
NecessaryTypeImplImports),
% Work out which module imports in the implementation section of
@@ -697,7 +698,7 @@ strip_unnecessary_impl_defns(Items0, Items) :-
% If a type in the implementation section isn't dummy and doesn't have
% foreign type alternatives, make it abstract.
- map.map_values(make_impl_type_abstract, !ImplTypesMap),
+ map.map_values(make_impl_type_abstract(BothTypesMap), !ImplTypesMap),
% If there is an exported type declaration for a type with an abstract
% declaration in the implementation (usually it will originally
@@ -898,15 +899,16 @@ insert_type_defn(New, [Head | Tail], Result) :-
Result = [Head | NewTail]
).
-:- pred make_impl_type_abstract(type_ctor::in,
+:- pred make_impl_type_abstract(type_defn_map::in, type_ctor::in,
assoc_list(type_defn, item_type_defn_info)::in,
assoc_list(type_defn, item_type_defn_info)::out) is det.
-make_impl_type_abstract(_TypeCtor, !TypeDefnPairs) :-
+make_impl_type_abstract(TypeDefnMap, _TypeCtor, !TypeDefnPairs) :-
(
!.TypeDefnPairs =
[parse_tree_du_type(Ctors, MaybeEqCmp) - ItemTypeDefn0],
- not constructor_list_represents_dummy_argument_type(Ctors, MaybeEqCmp)
+ not constructor_list_represents_dummy_argument_type(TypeDefnMap,
+ Ctors, MaybeEqCmp)
->
Defn = parse_tree_abstract_type(non_solver_type),
ItemTypeDefn = ItemTypeDefn0 ^ td_ctor_defn := Defn,
@@ -915,6 +917,84 @@ make_impl_type_abstract(_TypeCtor, !TypeDefnPairs) :-
true
).
+ % Certain types, e.g. io.state and store.store(S), are just dummy types
+ % used to ensure logical semantics; there is no need to actually pass them,
+ % and so when importing or exporting procedures to/from C, we don't include
+ % arguments with these types.
+ %
+ % See the documentation for `type_util.check_dummy_type' for the definition
+ % of a dummy type.
+ %
+ % NOTE: changes here may require changes to `type_util.check_dummy_type'.
+ %
+:- pred constructor_list_represents_dummy_argument_type(type_defn_map::in,
+ list(constructor)::in, maybe(unify_compare)::in) is semidet.
+
+constructor_list_represents_dummy_argument_type(TypeDefnMap,
+ Ctors, MaybeEqCmp) :-
+ constructor_list_represents_dummy_argument_type_2(TypeDefnMap,
+ Ctors, MaybeEqCmp, []).
+
+:- pred constructor_list_represents_dummy_argument_type_2(type_defn_map::in,
+ list(constructor)::in, maybe(unify_compare)::in, list(mer_type)::in)
+ is semidet.
+
+constructor_list_represents_dummy_argument_type_2(TypeDefnMap, [Ctor], no,
+ CoveredTypes) :-
+ Ctor = ctor(ExistQTVars, Constraints, _Name, Args, _Context),
+ ExistQTVars = [],
+ Constraints = [],
+ (
+ % A single zero-arity constructor.
+ Args = []
+ ;
+ % A constructor with a single argument.
+ Args = [ctor_arg(_, ArgType, _)],
+ ctor_arg_is_dummy_type(TypeDefnMap, ArgType, CoveredTypes) = yes
+ ).
+
+:- func ctor_arg_is_dummy_type(type_defn_map, mer_type, list(mer_type)) = bool.
+
+ctor_arg_is_dummy_type(TypeDefnMap, Type, CoveredTypes0) = IsDummyType :-
+ (
+ Type = defined_type(SymName, TypeArgs, _Kind),
+ ( list.member(Type, CoveredTypes0) ->
+ % The type is circular.
+ IsDummyType = no
+ ;
+ Arity = list.length(TypeArgs),
+ TypeCtor = type_ctor(SymName, Arity),
+ (
+ check_builtin_dummy_type_ctor(TypeCtor)
+ = is_builtin_dummy_type_ctor
+ ->
+ IsDummyType = yes
+ ;
+ % Can we find a definition of the type that tells us it is a
+ % dummy type?
+ multi_map.search(TypeDefnMap, TypeCtor, TypeDefns),
+ list.member(TypeDefn - _, TypeDefns),
+ TypeDefn = parse_tree_du_type(TypeCtors, MaybeEqCmp),
+ CoveredTypes = [Type | CoveredTypes0],
+ constructor_list_represents_dummy_argument_type_2(TypeDefnMap,
+ TypeCtors, MaybeEqCmp, CoveredTypes)
+ ->
+ IsDummyType = yes
+ ;
+ IsDummyType = no
+ )
+ )
+ ;
+ ( Type = type_variable(_, _)
+ ; Type = builtin_type(_)
+ ; Type = tuple_type(_, _)
+ ; Type = higher_order_type(_, _, _, _)
+ ; Type = apply_n_type(_, _, _)
+ ; Type = kinded_type(_, _)
+ ),
+ IsDummyType = no
+ ).
+
% strip_unnecessary_impl_imports(NecessaryModules, !Items):
%
% Remove all import_module and use_module declarations for
@@ -977,7 +1057,7 @@ is_not_unnecessary_impl_type(NecessaryTypeCtors, Item) :-
).
% get_requirements_of_impl_exported_types(InterfaceTypeMap, ImplTypeMap,
- % NecessaryTypeCtors, Modules):
+ % BothTypeMap, NecessaryTypeCtors, Modules):
%
% Figure out the set of abstract equivalence type constructors
% (i.e. the types that are exported as abstract types and which are defined
@@ -995,24 +1075,26 @@ is_not_unnecessary_impl_type(NecessaryTypeCtors, Item) :-
% in NecessaryTypeCtors.
%
:- pred get_requirements_of_impl_exported_types(type_defn_map::in,
- type_defn_map::in, set(type_ctor)::out, set(type_ctor)::out,
- set(module_name)::out) is det.
+ type_defn_map::in, type_defn_map::in,
+ set(type_ctor)::out, set(type_ctor)::out, set(module_name)::out) is det.
get_requirements_of_impl_exported_types(InterfaceTypeMap, ImplTypeMap,
- DummyTypeCtors, EqvTypeCtors, Modules) :-
+ BothTypeMap, DummyTypeCtors, EqvTypeCtors, Modules) :-
multi_map.to_flat_assoc_list(ImplTypeMap, ImplTypes),
- list.foldl2(accumulate_abs_impl_exported_type_lhs(InterfaceTypeMap),
+ list.foldl2(
+ accumulate_abs_impl_exported_type_lhs(InterfaceTypeMap, BothTypeMap),
ImplTypes, set.init, AbsEqvLhsTypeCtors, set.init, DummyTypeCtors),
set.fold2(accumulate_abs_eqv_type_rhs(ImplTypeMap), AbsEqvLhsTypeCtors,
set.init, AbsEqvRhsTypeCtors, set.init, Modules),
set.union(AbsEqvLhsTypeCtors, AbsEqvRhsTypeCtors, EqvTypeCtors).
:- pred accumulate_abs_impl_exported_type_lhs(type_defn_map::in,
+ type_defn_map::in,
pair(type_ctor, pair(type_defn, item_type_defn_info))::in,
set(type_ctor)::in, set(type_ctor)::out,
set(type_ctor)::in, set(type_ctor)::out) is det.
-accumulate_abs_impl_exported_type_lhs(InterfaceTypeMap,
+accumulate_abs_impl_exported_type_lhs(InterfaceTypeMap, BothTypesMap,
TypeCtor - (TypeDefn - _Item), !AbsEqvLhsTypeCtors, !DummyTypeCtors) :-
% A type may have multiple definitions because it may be defined both
% as a foreign type and as a Mercury type. We grab any equivalence types
@@ -1029,7 +1111,8 @@ accumulate_abs_impl_exported_type_lhs(InterfaceTypeMap,
svset.insert(TypeCtor, !AbsEqvLhsTypeCtors)
;
TypeDefn = parse_tree_du_type(Ctors, MaybeEqCmp),
- constructor_list_represents_dummy_argument_type(Ctors, MaybeEqCmp)
+ constructor_list_represents_dummy_argument_type(BothTypesMap,
+ Ctors, MaybeEqCmp)
->
svset.insert(TypeCtor, !DummyTypeCtors)
;
diff --git a/compiler/prog_type.m b/compiler/prog_type.m
index c81ae59..90a8a81 100644
--- a/compiler/prog_type.m
+++ b/compiler/prog_type.m
@@ -217,17 +217,6 @@
%
:- func check_builtin_dummy_type_ctor(type_ctor) = is_builtin_dummy_type_ctor.
- % Certain types, e.g. io.state and store.store(S), are just dummy types
- % used to ensure logical semantics; there is no need to actually pass them,
- % and so when importing or exporting procedures to/from C, we don't include
- % arguments with these types.
- %
- % A type is a dummy type in one of two cases: either it is a builtin
- % dummy type, or it has only a single function symbol of arity zero.
- %
-:- pred constructor_list_represents_dummy_argument_type(list(constructor)::in,
- maybe(unify_compare)::in) is semidet.
-
:- pred type_is_io_state(mer_type::in) is semidet.
:- pred type_ctor_is_array(type_ctor::in) is semidet.
@@ -809,9 +798,6 @@ check_builtin_dummy_type_ctor(TypeCtor) = IsBuiltinDummy :-
IsBuiltinDummy = is_not_builtin_dummy_type_ctor
).
-constructor_list_represents_dummy_argument_type([Ctor], no) :-
- Ctor = ctor([], [], _, [], _).
-
type_is_io_state(Type) :-
type_to_ctor_and_args(Type, TypeCtor, []),
ModuleName = mercury_std_lib_module_name(unqualified("io")),
diff --git a/compiler/type_util.m b/compiler/type_util.m
index 8ead00d..1609352 100644
--- a/compiler/type_util.m
+++ b/compiler/type_util.m
@@ -139,6 +139,9 @@
% A type cannot be a dummy type if it is the subject of a foreign_enum
% pragma, or if it has a reserved tag or user defined equality.
%
+ % NOTE: changes here may require changes to
+ % `modules.constructor_list_represents_dummy_argument_type'.
+ %
:- func check_dummy_type(module_info, mer_type) = is_dummy_type.
% A test for types that are defined in Mercury, but whose definitions
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index 0e0f138..ae288c9 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -56,6 +56,7 @@ ORDINARY_PROGS= \
dos \
dot_separator \
dst_test \
+ dummy_no_tag \
dummy_type_construct \
dupcall_impurity \
dupcall_types_bug \
diff --git a/tests/hard_coded/dummy_no_tag.exp b/tests/hard_coded/dummy_no_tag.exp
new file mode 100644
index 0000000..9f2228b
--- /dev/null
+++ b/tests/hard_coded/dummy_no_tag.exp
@@ -0,0 +1,3 @@
+no_tag_dummy(simple_dummy)
+no_tag_dummy(simple_dummy)
+no_tag_dummy(simple_dummy)
diff --git a/tests/hard_coded/dummy_no_tag.m b/tests/hard_coded/dummy_no_tag.m
new file mode 100644
index 0000000..028b08e
--- /dev/null
+++ b/tests/hard_coded/dummy_no_tag.m
@@ -0,0 +1,22 @@
+% Regression test. The compiler was not writing some dummy types to the
+% implementation sections of interface files, specifically types with one
+% constructor with one argument which is itself a dummy type.
+
+:- module dummy_no_tag.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module dummy_no_tag_2.
+
+main(!IO) :-
+ io.write(fun, !IO),
+ nl(!IO),
+ io.write(fun_eqv, !IO),
+ nl(!IO),
+ io.write(fun_eqv2, !IO),
+ nl(!IO).
diff --git a/tests/hard_coded/dummy_no_tag_2.m b/tests/hard_coded/dummy_no_tag_2.m
new file mode 100644
index 0000000..10bc5a8
--- /dev/null
+++ b/tests/hard_coded/dummy_no_tag_2.m
@@ -0,0 +1,31 @@
+:- module dummy_no_tag_2.
+:- interface.
+
+:- type no_tag_dummy.
+
+:- func fun = no_tag_dummy.
+
+:- type no_tag_dummy_eqv.
+:- type no_tag_dummy_eqv2.
+
+:- func fun_eqv = no_tag_dummy_eqv.
+:- func fun_eqv2 = no_tag_dummy_eqv2.
+
+:- implementation.
+
+:- type no_tag_dummy ---> no_tag_dummy(simple_dummy).
+
+:- type no_tag_dummy_eqv == no_tag_dummy.
+:- type no_tag_dummy_eqv2 == no_tag_dummy_eqv.
+
+:- type simple_dummy ---> simple_dummy.
+
+% check circular types
+:- type not_dummy_a ---> not_dummy_a(not_dummy_b).
+:- type not_dummy_b ---> not_dummy_b(not_dummy_a).
+
+fun = no_tag_dummy(simple_dummy).
+
+fun_eqv = fun.
+
+fun_eqv2 = fun.
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to: mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the reviews
mailing list