@@ -23,8 +23,9 @@ import com.squareup.kotlinpoet.ParameterSpec
2323import com.squareup.kotlinpoet.ParameterizedTypeName
2424import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
2525import com.squareup.kotlinpoet.PropertySpec
26+ import com.squareup.kotlinpoet.TypeVariableName
2627import com.squareup.kotlinpoet.asTypeName
27- import org.modelix.metamodel.ITypedConcept
28+ import org.modelix.metamodel.IConceptOfTypedNode
2829import org.modelix.metamodel.generator.MetaModelGenerator
2930import org.modelix.metamodel.generator.NameConfig
3031import org.modelix.metamodel.generator.ProcessedChildLink
@@ -66,6 +67,9 @@ internal class ModelQLExtensionsGenerator(
6667 is ProcessedChildLink -> {
6768 addChildGetter(feature)
6869 addChildSetter(feature)
70+ if (! feature.type.resolved.abstract) {
71+ addDefaultChildSetter(feature)
72+ }
6973 }
7074
7175 is ProcessedReferenceLink -> {
@@ -80,7 +84,7 @@ internal class ModelQLExtensionsGenerator(
8084
8185 private fun FileSpec.Builder.addReferenceSetter (referenceLink : ProcessedReferenceLink ) {
8286 val targetType = referenceLink.type.resolved.nodeWrapperInterfaceType().copy(nullable = referenceLink.optional)
83- val inputStepType = IMonoStep :: class .asTypeName().parameterizedBy(concept.nodeWrapperInterfaceType() )
87+ val inputStepType = getSetterReceiverType( )
8488
8589 val parameterType = IMonoStep ::class .asTypeName().parameterizedBy(targetType)
8690 .let { if (referenceLink.optional) it.copy(nullable = true ) else it }
@@ -159,26 +163,23 @@ internal class ModelQLExtensionsGenerator(
159163
160164 private fun FileSpec.Builder.addChildSetter (childLink : ProcessedChildLink ) {
161165 val targetType = childLink.type.resolved.nodeWrapperInterfaceType()
162- val returnType = IMonoStep :: class .asTypeName().parameterizedBy( targetType)
163- val receiverType = IMonoStep ::class .asTypeName().parameterizedBy(concept.nodeWrapperInterfaceType() )
164- val conceptParameter = ParameterSpec .builder( " concept " , ITypedConcept :: class .asTypeName()). apply {
165- if ( ! childLink.type.resolved.abstract) {
166- defaultValue( " %T " , childLink.type.resolved.conceptWrapperInterfaceClass())
167- }
168- } .build()
166+ val outType = TypeVariableName ( " Out " , targetType)
167+ val returnType = IMonoStep ::class .asTypeName().parameterizedBy(outType )
168+ val receiverType = getSetterReceiverType()
169+ val conceptParameter = ParameterSpec .builder(
170+ name = " concept " ,
171+ type = IConceptOfTypedNode :: class .asTypeName().parameterizedBy(outType),
172+ ) .build()
169173
170- val funName = if (childLink.multiple) childLink.adderMethodName() else childLink.setterName( )
174+ val funName = getSetterName (childLink)
171175
172176 val funSpec = FunSpec .builder(funName).runBuild {
177+ addTypeVariable(outType)
173178 returns(returnType)
174179 receiver(receiverType)
175180 addParameter(conceptParameter)
176181 if (childLink.multiple) {
177- val indexParameter = ParameterSpec .builder(" index" , Int ::class .asTypeName())
178- .defaultValue(" -1" )
179- .build()
180-
181- addParameter(indexParameter)
182+ addIndexParameter()
182183 addStatement(
183184 " return %T.addNewChild(this, %T.%N, index, concept)" ,
184185 TypedModelQL ::class .asTypeName(),
@@ -198,6 +199,55 @@ internal class ModelQLExtensionsGenerator(
198199 addFunction(funSpec)
199200 }
200201
202+ /*
203+ If we use the concept companion object as a default value for the concept parameter,
204+ the kotlin compiler reports a type mismatch since it cannot properly infer the type variable.
205+ That's why we need a separate default setter.
206+ */
207+ private fun FileSpec.Builder.addDefaultChildSetter (childLink : ProcessedChildLink ) {
208+ val targetType = childLink.type.resolved.conceptWrapperInterfaceClass()
209+ val returnType = IMonoStep ::class .asTypeName().parameterizedBy(childLink.type.resolved.nodeWrapperInterfaceType())
210+ val receiverType = getSetterReceiverType()
211+
212+ val funName = getSetterName(childLink)
213+
214+ val funSpec = FunSpec .builder(funName).runBuild {
215+ returns(returnType)
216+ receiver(receiverType)
217+ if (childLink.multiple) {
218+ addIndexParameter()
219+ addStatement(
220+ " return %T.addNewChild(this, %T.%N, index, %T)" ,
221+ TypedModelQL ::class .asTypeName(),
222+ concept.conceptObjectType(),
223+ childLink.generatedName,
224+ targetType,
225+ )
226+ } else {
227+ addStatement(
228+ " return %T.setChild(this, %T.%N, %T)" ,
229+ TypedModelQL ::class .asTypeName(),
230+ concept.conceptObjectType(),
231+ childLink.generatedName,
232+ targetType,
233+ )
234+ }
235+ }
236+
237+ addFunction(funSpec)
238+ }
239+
240+ private fun FunSpec.Builder.addIndexParameter () {
241+ val indexParameter = ParameterSpec .builder(" index" , Int ::class .asTypeName())
242+ .defaultValue(" -1" )
243+ .build()
244+
245+ addParameter(indexParameter)
246+ }
247+
248+ private fun getSetterName (childLink : ProcessedChildLink ) =
249+ if (childLink.multiple) childLink.adderMethodName() else childLink.setterName()
250+
201251 private fun FileSpec.Builder.addChildGetter (childLink : ProcessedChildLink ) {
202252 val inputStepType = (if (childLink.multiple) IProducingStep ::class else IMonoStep ::class).asTypeName()
203253 val outputStepType = (if (childLink.multiple) IFluxStep ::class else IMonoStep ::class).asTypeName()
@@ -225,8 +275,7 @@ internal class ModelQLExtensionsGenerator(
225275 }
226276
227277 private fun FileSpec.Builder.addPropertySetter (property : ProcessedProperty ) {
228- val inputStepType = IMonoStep ::class .asTypeName()
229- .parameterizedBy(concept.nodeWrapperInterfaceType())
278+ val inputStepType = getSetterReceiverType()
230279
231280 val parameterType = IMonoStep ::class .asTypeName()
232281 .parameterizedBy(property.asKotlinType(alwaysUseNonNullableProperties))
@@ -246,6 +295,9 @@ internal class ModelQLExtensionsGenerator(
246295 addFunction(setterSpec)
247296 }
248297
298+ private fun getSetterReceiverType () =
299+ IMonoStep ::class .asTypeName().parameterizedBy(concept.nodeWrapperInterfaceType())
300+
249301 private fun FileSpec.Builder.addPropertyGetterForStepType (
250302 property : ProcessedProperty ,
251303 stepType : ClassName ,
0 commit comments