diff --git a/lib/attr.gd b/lib/attr.gd
index 155d6a643f..2b347bc6e5 100644
--- a/lib/attr.gd
+++ b/lib/attr.gd
@@ -36,10 +36,14 @@
##
##
##
-## This info class (together with is used
-## for messages about attribute storing being disabled (at level 2) or
-## enabled (level 3). It may be used in the future for other messages
-## concerning changes to attribute behaviour.
+## This info class (together with ) is used
+## for messages about attributes. Messages are shown under the following circumstances:
+##
+## -
is used (level 2).
+## -
is used (level 3).
+## - When trying to assign to non-mutable attribute which already is set to a different value (level 3).
+## - When the test filter for an attribute (i.e., HasFOO) is set, but no value is assigned (level 3).
+##
##
##
## <#/GAPDoc>
diff --git a/lib/attr.gi b/lib/attr.gi
index b7cb9edcc5..79f04e386c 100644
--- a/lib/attr.gi
+++ b/lib/attr.gi
@@ -37,3 +37,13 @@ InstallGlobalFunction(DisableAttributeValueStoring, function( attr )
Info(InfoAttributes + InfoWarning, 2, "Disabling value storing for ",NAME_FUNC(attr));
SET_ATTRIBUTE_STORING( attr, false);
end);
+
+CHECK_REPEATED_ATTRIBUTE_SET := function(obj, name, val)
+ if InfoLevel(InfoAttributes) >= 3 then
+ if not IsBound(obj!.(name)) then
+ Info(InfoAttributes, 3, "Attribute ", name, " of ", obj, " is marked as assigned, but it has no value");
+ elif obj!.(name) <> val then
+ Info(InfoAttributes, 3, "Attribute ", name, " of ", obj, " already set to ", obj!.(name), ", cannot be changed to ", val);
+ fi;
+ fi;
+end;
diff --git a/lib/coll.gi b/lib/coll.gi
index 3af9cc4f18..5ee18a3c63 100644
--- a/lib/coll.gi
+++ b/lib/coll.gi
@@ -3105,13 +3105,7 @@ InstallOtherMethod(SetSize,true,[IsObject and IsAttributeStoringRep,IsObject],
function(obj,sz)
local filt;
if HasSize(obj) and Size(obj)<>sz then
- if AssertionLevel()>2 then
- # Make this an ordinary error (not ErrorNoReturn as suggested) to
- # preserve all debugging options -- even use `return` to investigate
- # what would have happened before this methods was introduced.
- Error("size of ",obj," already set to ",Size(obj),
- ", cannot be changed to ",sz);
- fi;
+ CHECK_REPEATED_ATTRIBUTE_SET(obj, "Size", sz);
return;
fi;
if sz=0 then filt:=IsEmpty;
diff --git a/lib/module.gi b/lib/module.gi
index 6969b7cfd9..46df47ba76 100644
--- a/lib/module.gi
+++ b/lib/module.gi
@@ -415,7 +415,7 @@ InstallOtherMethod(SetDimension,true,[IsObject and IsAttributeStoringRep,IsObjec
function(obj,dim)
local filt;
if HasDimension(obj) and IsBound(obj!.Dimension) then
- Assert(2, Dimension(obj) = dim);
+ CHECK_REPEATED_ATTRIBUTE_SET(obj, "Dimension", dim);
return;
fi;
if dim=0 then
diff --git a/lib/oper1.g b/lib/oper1.g
index da7afe5f83..ff000facb3 100644
--- a/lib/oper1.g
+++ b/lib/oper1.g
@@ -1090,3 +1090,7 @@ InstallMethod( ViewObj,
[ IS_OBJECT ],
0,
PRINT_OBJ );
+
+# A dummy version of this function is installed here, the full version
+# is defined in attr.gi, after Info-related functionality is set up.
+CHECK_REPEATED_ATTRIBUTE_SET := function(obj, name, val) end;
diff --git a/src/c_oper1.c b/src/c_oper1.c
index c91e9a2eb5..e7a8dca154 100644
--- a/src/c_oper1.c
+++ b/src/c_oper1.c
@@ -1,7 +1,7 @@
#ifndef AVOID_PRECOMPILED
/* C file produced by GAC */
#include "compiled.h"
-#define FILE_CRC "-77878372"
+#define FILE_CRC "-76837766"
/* global variables used in handlers */
static GVar G_REREADING;
@@ -24,6 +24,7 @@ static GVar G_SET__NAME__FUNC;
static Obj GF_SET__NAME__FUNC;
static GVar G_NARG__FUNC;
static Obj GF_NARG__FUNC;
+static GVar G_CHECK__REPEATED__ATTRIBUTE__SET;
static GVar G_IS__OPERATION;
static Obj GF_IS__OPERATION;
static GVar G_AINV;
@@ -181,7 +182,7 @@ static RNam R_CommandLineOptions;
static RNam R_N;
/* information for the functions */
-static Obj NameFunc[19];
+static Obj NameFunc[20];
static Obj FileName;
/* handler for function 2 */
@@ -5184,6 +5185,27 @@ static Obj HdlrFunc17 (
return 0;
}
+/* handler for function 19 */
+static Obj HdlrFunc19 (
+ Obj self,
+ Obj a_obj,
+ Obj a_name,
+ Obj a_val )
+{
+ Bag oldFrame;
+
+ /* allocate new stack frame */
+ SWITCH_TO_NEW_FRAME(self,0,0,oldFrame);
+
+ /* return; */
+ SWITCH_TO_OLD_FRAME(oldFrame);
+ return 0;
+
+ /* return; */
+ SWITCH_TO_OLD_FRAME(oldFrame);
+ return 0;
+}
+
/* handler for function 1 */
static Obj HdlrFunc1 (
Obj self )
@@ -5907,6 +5929,18 @@ static Obj HdlrFunc1 (
DoOperation2Args( CallFuncListOper, t_1, NewPlistFromArgs( t_2, t_3, t_4, t_5, INTOBJ_INT(0), t_6 ) );
}
+ /* CHECK_REPEATED_ATTRIBUTE_SET := function ( obj, name, val )
+ return;
+ end; */
+ t_1 = NewFunction( NameFunc[19], 3, ArgStringToList("obj,name,val"), HdlrFunc19 );
+ SET_ENVI_FUNC( t_1, STATE(CurrLVars) );
+ t_2 = NewFunctionBody();
+ SET_STARTLINE_BODY(t_2, 1096);
+ SET_ENDLINE_BODY(t_2, 1096);
+ SET_FILENAME_BODY(t_2, FileName);
+ SET_BODY_FUNC(t_1, t_2);
+ AssGVar( G_CHECK__REPEATED__ATTRIBUTE__SET, t_1 );
+
/* return; */
SWITCH_TO_OLD_FRAME(oldFrame);
return 0;
@@ -5931,6 +5965,7 @@ static Int PostRestore ( StructInitInfo * module )
G_NAME__FUNC = GVarName( "NAME_FUNC" );
G_SET__NAME__FUNC = GVarName( "SET_NAME_FUNC" );
G_NARG__FUNC = GVarName( "NARG_FUNC" );
+ G_CHECK__REPEATED__ATTRIBUTE__SET = GVarName( "CHECK_REPEATED_ATTRIBUTE_SET" );
G_IS__OPERATION = GVarName( "IS_OPERATION" );
G_AINV = GVarName( "AINV" );
G_IS__INT = GVarName( "IS_INT" );
@@ -6031,6 +6066,7 @@ static Int PostRestore ( StructInitInfo * module )
NameFunc[16] = 0;
NameFunc[17] = 0;
NameFunc[18] = 0;
+ NameFunc[19] = 0;
/* return success */
return 0;
@@ -6167,6 +6203,8 @@ static Int InitKernel ( StructInitInfo * module )
InitGlobalBag( &(NameFunc[17]), "GAPROOT/lib/oper1.g:NameFunc[17]("FILE_CRC")" );
InitHandlerFunc( HdlrFunc18, "GAPROOT/lib/oper1.g:HdlrFunc18("FILE_CRC")" );
InitGlobalBag( &(NameFunc[18]), "GAPROOT/lib/oper1.g:NameFunc[18]("FILE_CRC")" );
+ InitHandlerFunc( HdlrFunc19, "GAPROOT/lib/oper1.g:HdlrFunc19("FILE_CRC")" );
+ InitGlobalBag( &(NameFunc[19]), "GAPROOT/lib/oper1.g:NameFunc[19]("FILE_CRC")" );
/* return success */
return 0;
@@ -6201,7 +6239,7 @@ static Int InitLibrary ( StructInitInfo * module )
static StructInitInfo module = {
.type = MODULE_STATIC,
.name = "GAPROOT/lib/oper1.g",
- .crc = -77878372,
+ .crc = -76837766,
.initKernel = InitKernel,
.initLibrary = InitLibrary,
.postRestore = PostRestore,
diff --git a/src/hpc/c_oper1.c b/src/hpc/c_oper1.c
index cff23df95f..15ee00a4c8 100644
--- a/src/hpc/c_oper1.c
+++ b/src/hpc/c_oper1.c
@@ -1,7 +1,7 @@
#ifndef AVOID_PRECOMPILED
/* C file produced by GAC */
#include "compiled.h"
-#define FILE_CRC "-77878372"
+#define FILE_CRC "-76837766"
/* global variables used in handlers */
static GVar G_REREADING;
@@ -24,6 +24,7 @@ static GVar G_SET__NAME__FUNC;
static Obj GF_SET__NAME__FUNC;
static GVar G_NARG__FUNC;
static Obj GF_NARG__FUNC;
+static GVar G_CHECK__REPEATED__ATTRIBUTE__SET;
static GVar G_IS__OPERATION;
static Obj GF_IS__OPERATION;
static GVar G_AINV;
@@ -197,7 +198,7 @@ static RNam R_CommandLineOptions;
static RNam R_N;
/* information for the functions */
-static Obj NameFunc[19];
+static Obj NameFunc[20];
static Obj FileName;
/* handler for function 2 */
@@ -5309,6 +5310,27 @@ static Obj HdlrFunc17 (
return 0;
}
+/* handler for function 19 */
+static Obj HdlrFunc19 (
+ Obj self,
+ Obj a_obj,
+ Obj a_name,
+ Obj a_val )
+{
+ Bag oldFrame;
+
+ /* allocate new stack frame */
+ SWITCH_TO_NEW_FRAME(self,0,0,oldFrame);
+
+ /* return; */
+ SWITCH_TO_OLD_FRAME(oldFrame);
+ return 0;
+
+ /* return; */
+ SWITCH_TO_OLD_FRAME(oldFrame);
+ return 0;
+}
+
/* handler for function 1 */
static Obj HdlrFunc1 (
Obj self )
@@ -6052,6 +6074,18 @@ static Obj HdlrFunc1 (
DoOperation2Args( CallFuncListOper, t_1, NewPlistFromArgs( t_2, t_3, t_4, t_5, INTOBJ_INT(0), t_6 ) );
}
+ /* CHECK_REPEATED_ATTRIBUTE_SET := function ( obj, name, val )
+ return;
+ end; */
+ t_1 = NewFunction( NameFunc[19], 3, ArgStringToList("obj,name,val"), HdlrFunc19 );
+ SET_ENVI_FUNC( t_1, STATE(CurrLVars) );
+ t_2 = NewFunctionBody();
+ SET_STARTLINE_BODY(t_2, 1096);
+ SET_ENDLINE_BODY(t_2, 1096);
+ SET_FILENAME_BODY(t_2, FileName);
+ SET_BODY_FUNC(t_1, t_2);
+ AssGVar( G_CHECK__REPEATED__ATTRIBUTE__SET, t_1 );
+
/* return; */
SWITCH_TO_OLD_FRAME(oldFrame);
return 0;
@@ -6076,6 +6110,7 @@ static Int PostRestore ( StructInitInfo * module )
G_NAME__FUNC = GVarName( "NAME_FUNC" );
G_SET__NAME__FUNC = GVarName( "SET_NAME_FUNC" );
G_NARG__FUNC = GVarName( "NARG_FUNC" );
+ G_CHECK__REPEATED__ATTRIBUTE__SET = GVarName( "CHECK_REPEATED_ATTRIBUTE_SET" );
G_IS__OPERATION = GVarName( "IS_OPERATION" );
G_AINV = GVarName( "AINV" );
G_IS__INT = GVarName( "IS_INT" );
@@ -6184,6 +6219,7 @@ static Int PostRestore ( StructInitInfo * module )
NameFunc[16] = 0;
NameFunc[17] = 0;
NameFunc[18] = 0;
+ NameFunc[19] = 0;
/* return success */
return 0;
@@ -6328,6 +6364,8 @@ static Int InitKernel ( StructInitInfo * module )
InitGlobalBag( &(NameFunc[17]), "GAPROOT/lib/oper1.g:NameFunc[17]("FILE_CRC")" );
InitHandlerFunc( HdlrFunc18, "GAPROOT/lib/oper1.g:HdlrFunc18("FILE_CRC")" );
InitGlobalBag( &(NameFunc[18]), "GAPROOT/lib/oper1.g:NameFunc[18]("FILE_CRC")" );
+ InitHandlerFunc( HdlrFunc19, "GAPROOT/lib/oper1.g:HdlrFunc19("FILE_CRC")" );
+ InitGlobalBag( &(NameFunc[19]), "GAPROOT/lib/oper1.g:NameFunc[19]("FILE_CRC")" );
/* return success */
return 0;
@@ -6362,7 +6400,7 @@ static Int InitLibrary ( StructInitInfo * module )
static StructInitInfo module = {
.type = MODULE_STATIC,
.name = "GAPROOT/lib/oper1.g",
- .crc = -77878372,
+ .crc = -76837766,
.initKernel = InitKernel,
.initLibrary = InitLibrary,
.postRestore = PostRestore,
diff --git a/src/opers.c b/src/opers.c
index f5d4fb94ca..729295462f 100644
--- a/src/opers.c
+++ b/src/opers.c
@@ -1385,6 +1385,7 @@ static UInt RNamIsVerbose;
static UInt RNamIsConstructor;
static UInt RNamPrecedence;
static Obj HANDLE_METHOD_NOT_FOUND;
+static Obj CHECK_REPEATED_ATTRIBUTE_SET;
static void HandleMethodNotFound(Obj oper,
Int nargs,
@@ -3283,12 +3284,15 @@ static Obj DoSetterFunction(Obj self, Obj obj, Obj value)
flag2 = INT_INTOBJ( FLAG2_FILT(tester) );
type = TYPE_OBJ_FEO(obj);
flags = FLAGS_TYPE(type);
+
+ UInt rnam = (UInt)INT_INTOBJ(ELM_PLIST(tmp, 1));
+
if ( SAFE_C_ELM_FLAGS(flags,flag2) ) {
+ CALL_3ARGS(CHECK_REPEATED_ATTRIBUTE_SET, obj, NAME_RNAM(rnam), value);
return 0;
}
/* set the value */
- UInt rnam = (UInt)INT_INTOBJ(ELM_PLIST(tmp,1));
#ifdef HPCGAP
if (atomic)
SetARecordField( obj, rnam, CopyObj(value,0) );
@@ -3772,6 +3776,9 @@ static Int InitKernel (
ImportFuncFromLibrary("HANDLE_METHOD_NOT_FOUND",
&HANDLE_METHOD_NOT_FOUND);
+ ImportFuncFromLibrary("CHECK_REPEATED_ATTRIBUTE_SET",
+ &CHECK_REPEATED_ATTRIBUTE_SET);
+
#ifdef GASMAN
ImportGVarFromLibrary( "IsType", &IsType );
ImportFuncFromLibrary( "FLUSH_ALL_METHOD_CACHES", &FLUSH_ALL_METHOD_CACHES );
diff --git a/tst/testinstall/attribute.tst b/tst/testinstall/attribute.tst
index bc88fd2dcf..7795b56877 100644
--- a/tst/testinstall/attribute.tst
+++ b/tst/testinstall/attribute.tst
@@ -1,4 +1,6 @@
gap> START_TEST("attribute.tst");
+gap> attributeinfo := InfoLevel(InfoAttributes);;
+gap> SetInfoLevel(InfoAttributes, 3);
gap> DeclareAttribute();
Error, Function: number of arguments must be at least 2 (not 0)
gap> DeclareAttribute("banana");
@@ -60,6 +62,19 @@ gap> HasSize(foo);
true
gap> Size(foo);
17
+gap> SetSize(foo, 16);
+#I Attribute Size of