diff --git a/lib/attr.gd b/lib/attr.gd
index bfbf6bec1c3..9d0d14d725f 100644
--- a/lib/attr.gd
+++ b/lib/attr.gd
@@ -37,8 +37,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
+## for messages about attributes. The current warnings are:
+##
+## - Attribute storing being disabled (level 2)
+## - Atribute storing being enabled (level 3)
+## - Trying to assign a non-mutable attribute a different value (level 3)
+## - An attribute which is marked as assigned, but has no value (level 3)
+##
+## It may be used in the future for other messages
## concerning changes to attribute behaviour.
##
##
diff --git a/lib/attr.gi b/lib/attr.gi
index 4d17d8d24be..2ee6f815f78 100644
--- a/lib/attr.gi
+++ b/lib/attr.gi
@@ -37,3 +37,11 @@ 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 not IsBound(obj!.(name)) then
+ Info(InfoAttributes + InfoWarning, 3, "Attribute ", name, " of ", obj, " is marked as assigned, but it has no value");
+ elif obj!.(name) <> val then
+ Info(InfoAttributes + InfoWarning, 3, name, " of ", obj, " already set to ", obj!.(name), ", cannot be changed to ", val);
+ fi;
+end;
diff --git a/lib/coll.gi b/lib/coll.gi
index 54435d672aa..730417c412c 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/oper1.g b/lib/oper1.g
index 61c2e9e822e..015f02b3863 100644
--- a/lib/oper1.g
+++ b/lib/oper1.g
@@ -1090,3 +1090,7 @@ InstallMethod( ViewObj,
[ IS_OBJECT ],
0,
PRINT_OBJ );
+
+# An dummy version of this function is installed here, the full version
+# is installed in attr.gd, 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 bcfb9d4b410..bfe4db925c7 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 "50470712"
+#define FILE_CRC "19934316"
/* 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 = 50470712,
+ .crc = 19934316,
.initKernel = InitKernel,
.initLibrary = InitLibrary,
.postRestore = PostRestore,
diff --git a/src/hpc/c_oper1.c b/src/hpc/c_oper1.c
index f98590b9b62..3a3eb51c7bd 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 "50470712"
+#define FILE_CRC "19934316"
/* 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 = 50470712,
+ .crc = 19934316,
.initKernel = InitKernel,
.initLibrary = InitLibrary,
.postRestore = PostRestore,
diff --git a/src/opers.c b/src/opers.c
index f5d4fb94caf..fabea7dcefc 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 bc88fd2dcf7..14b57b6bf56 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,10 @@ gap> HasSize(foo);
true
gap> Size(foo);
17
+gap> SetSize(foo, 16);
+#I Size of