@@ -15,15 +15,9 @@ import org.evomaster.core.Lazy
1515import org.evomaster.core.problem.enterprise.EnterpriseIndividual
1616import org.evomaster.core.problem.enterprise.SampleType
1717import org.evomaster.core.search.RootElement
18- import org.evomaster.core.search.gene.sql.SqlAutoIncrementGene
19- import org.evomaster.core.search.gene.sql.SqlPrimaryKeyGene
18+ import org.evomaster.core.search.gene.interfaces.TaintableGene
2019import org.evomaster.core.search.gene.utils.GeneUtils
21- import org.evomaster.core.search.gene.wrapper.CustomMutationRateGene
22- import org.evomaster.core.search.gene.wrapper.FlexibleGene
23- import org.evomaster.core.search.gene.wrapper.NullableGene
24- import org.evomaster.core.search.gene.wrapper.OptionalGene
25- import org.evomaster.core.search.gene.wrapper.SelectableWrapperGene
26- import org.evomaster.core.search.gene.wrapper.WrapperGene
20+ import org.evomaster.core.search.gene.interfaces.WrapperGene
2721import org.evomaster.core.search.service.SearchGlobalState
2822import org.evomaster.core.search.service.monitor.ProcessMonitorExcludeField
2923
@@ -349,6 +343,17 @@ abstract class Gene(
349343 return this
350344 }
351345
346+ /* *
347+ * Return the gene used for the phenotype.
348+ * Most of the time this would be `this` gene.
349+ * Note, it is different from the concept of "wrapper", as the wrapper itself can impact
350+ * the phenotype.
351+ *
352+ * This is mainly used to handle very special cases such as [StringGene] and [SeededGene]
353+ */
354+ open fun getPhenotype () : Gene {
355+ return this
356+ }
352357
353358
354359 protected fun matchingClass (klass : Class <* >, strict : Boolean ): Boolean {
@@ -906,19 +911,22 @@ abstract class Gene(
906911 * sync [bindingGenes] based on [this]
907912 */
908913 fun syncBindingGenesBasedOnThis (all : MutableSet <Gene > = mutableSetOf()) {
909- if (bindingGenes.isEmpty()) return
914+ if (bindingGenes.isEmpty()){
915+ return
916+ }
910917 all.add(this )
911918 bindingGenes.filterNot { all.contains(it) }.forEach { b ->
912919 all.add(b)
913- if (! b.setValueBasedOn(this ))
914- LoggingUtil .uniqueWarn(
915- log,
916- " fail to bind the gene (${b.name} with the type ${b::class .java.simpleName} ) based on this gene (${this .name} with ${this ::class .java.simpleName} )"
917- )
920+ if (! b.copyValueFrom(this )) {
921+ LoggingUtil .uniqueWarn(log, " fail to bind the gene (${b.name} with the type ${b::class .java.simpleName} )" +
922+ " based on this gene (${this .name} with ${this ::class .java.simpleName} )" )
923+ }
918924 b.syncBindingGenesBasedOnThis(all)
919925 }
920926
921- children.filterNot { all.contains(it) }.forEach { it.syncBindingGenesBasedOnThis(all) }
927+ children.filterNot { all.contains(it) }.forEach {
928+ it.syncBindingGenesBasedOnThis(all)
929+ }
922930 }
923931
924932 /* *
@@ -1110,62 +1118,52 @@ abstract class Gene(
11101118 * The type of genes can be different.
11111119 * However, there is no check if constraints are kept satisfied.
11121120 * So, this method should not be called directly.
1113- * Rather use [setFromDifferentGene ], which internally it calls this method,
1121+ * Rather use [copyValueFrom ], which internally it calls this method,
11141122 * and then revert in case of constraint violations.
11151123 *
1116- * @return whether the binding performs successfully.
1124+ * @return whether the value is copied based on [other] successfully.
1125+ * This is based only on the gene type.
1126+ * _WARNING_:
1127+ * - `true` might still leave the gene in an inconsistent state (ie violated constraints)
1128+ * - `false` might still apply partial updates (eg, think of an objects with several fields)
1129+ *
1130+ * Do not call directly outside this package. Call [copyValueFrom]
11171131 *
11181132 * TODO unfortunately, Kotlin has major design flows that do not allow package-level and true protected-level
11191133 * scope, like in Java :(
11201134 * This is a case in which is much worse than Java.
11211135 * But it could be simulated with Detekt and a rule like @PackagePrivate
11221136 */
1123- @Deprecated(" Do not call directly outside this package. Call setFromDifferentGene" )
1124- // TODO remove deprecated once we integrate @PackagePrivate
1125- internal abstract fun setValueBasedOn (gene : Gene ): Boolean
1137+ abstract fun unsafeCopyValueFrom (other : Gene ): Boolean
11261138
11271139
1128- /* *
1129- * copy value based on [other]
1130- * in some case, the [other] might not satisfy constraints of [this gene],
1131- * then copying will not be performed successfully
1132- *
1133- * FIXME unclear if side-effects or not
1134- *
1135- * @return whether the value is copied based on [other] successfully
1136- */
1137- abstract fun copyValueFrom (other : Gene ): Boolean
1138-
1140+ fun forceNewTaints (){
1141+ flatView().forEach { r ->
1142+ if (r is TaintableGene && ! r.isDependentTaint()){
1143+ r.forceNewTaintId()
1144+ }
1145+ }
1146+ }
11391147
11401148 /* *
1141- * Update current value of this gene, base on other gene.
1142- * This is not [copyValueFrom], as the gene could be different.
1143- * FIXME that comment seems wrong
1149+ * Update current value of this gene, base on [other] gene.
11441150 * If for any reason the update fails, there is not going to be any side-effects.
1151+ * A successful update must guarantee that the gene remains valid (ie, no violated constraints).
11451152 *
11461153 * @return if the update was successful
11471154 */
1148- fun setFromDifferentGene (gene : Gene , undoIfUpdateFails : Boolean = true): Boolean {
1149-
1150- // FIXME current implementation leads to infinite loops. must fix copyValueFrom
1151- // return updateValueOnlyIfValid( { setValueBasedOn(gene) } , undoIfUpdateFails)
1152- // TODO update once fixed
1153- return setValueBasedOn(gene)
1155+ fun copyValueFrom (gene : Gene ): Boolean {
1156+ return updateValueOnlyIfValid( { unsafeCopyValueFrom(gene) }, true )
11541157 }
11551158
1156- /*
1157- FIXME: looks like redundancies and inconsistencies between copyValueFrom and setFromDifferentGene.
1158- TODO once fixed, update
1159- */
1160-
11611159 /* *
11621160 * Given a string value, apply it to the current state of this gene (and possibly recursively to its children).
11631161 * If it fails for any reason, return false.
11641162 * This method guarantees the validity of the resulting gene, ie, changes are reverted if any constraints
11651163 * is violated.
11661164 */
11671165 fun setFromStringValue (value : String , undoIfUpdateFails : Boolean = true): Boolean {
1168- return updateValueOnlyIfValid({ setValueBasedOn (value) }, undoIfUpdateFails)
1166+ return updateValueOnlyIfValid({ unsafeSetFromStringValue (value) }, undoIfUpdateFails)
11691167 }
11701168
11711169 /* *
@@ -1181,33 +1179,42 @@ abstract class Gene(
11811179 * TODO @PackagePrivate
11821180 */
11831181 @Deprecated(" Do not call directly outside this package. Call setFromStringValue" )
1184- internal open fun setValueBasedOn (value : String ): Boolean {
1182+ internal open fun unsafeSetFromStringValue (value : String ): Boolean {
11851183 // TODO in future this should be abstract, to force each gene to handle it.
11861184 // few implementations can be based on AbstractParser class for Postman
11871185 throw IllegalStateException (" setValueBasedOn() is not implemented for gene ${this ::class .simpleName} " )
11881186 }
11891187
11901188
11911189 /* *
1192- * here `valid` means that 1) [updateValue] performs correctly, ie, returns true AND 2) isLocallyValid is true
1190+ * here `valid` means that 1) [updateValue] performs correctly, ie, returns true AND 2) [isGloballyValid] is true
11931191 *
11941192 * @param updateValue lambda performs update of value of the gene
1195- * @param undoIfUpdateFails represents whether it needs to undo the value update if [undoIfUpdateFails ] returns false
1193+ * @param undoIfUpdateFails represents whether it needs to undo the value update if [updateValue ] returns false
11961194 *
1197- * @return if the value is updated with [updateValue]
1195+ * @return if the value is updated with [updateValue]. note if for any reason the current gene was not valid,
1196+ * the validity of the update will not be checked.
11981197 */
11991198 fun updateValueOnlyIfValid (updateValue : () -> Boolean , undoIfUpdateFails : Boolean ): Boolean {
1199+
1200+ if (! undoIfUpdateFails) {
1201+ return updateValue()
1202+ }
1203+
1204+ val currentlyValid = isGloballyValid()
1205+
12001206 val current = copy()
12011207 val ok = updateValue()
1202- if (! ok && ! undoIfUpdateFails) return false
12031208
1204- if (! ok || ! isLocallyValid()) {
1205- val success = copyValueFrom(current)
1206- assert (success)
1209+ if (! ok || (currentlyValid && ! isGloballyValid())) {
1210+ // revert back
1211+ val success = unsafeCopyValueFrom(current)
1212+ // reversion should always work... if fails, it is a bug
1213+ // FIXME put back once all are implemented, eg, TaintedMapGene currently missing
1214+ // assert(success)
12071215 return false
12081216 }
12091217 return true
1210-
12111218 }
12121219
12131220 /* *
0 commit comments