Skip to content

Commit

Permalink
Filter mixins that have different types (#1510)
Browse files Browse the repository at this point in the history
* Filter mixins that have different types

Similar to what was done in #425, I've filtered out the
mixins that have different type than the final shape they're
applied to.

As such, in the example above, `HasName` has a optional name
member where as `Person` inherits the mixin but makes the member
required. The filtering catches that and as a result the mixin is
removed from the list of mixins to add on `Person`.

This behaviour aligns with the behaviour that happens when no `@adt`
trait is added and `Person` is code generated on it's own. In both
cases, now, the trait `HasName` is not extended because the types of
`name` don't align.
  • Loading branch information
daddykotex authored May 8, 2024
1 parent 001bb47 commit 5480e8e
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Constraints applied to list or map members are now correctly rendered in the generated code.
* Fix an issue with duplicated entries in generated smithy-build.json file (#1491)
* Add support for passing custom OpenAPI config via a `smithy-build.json` file
* Fix a bug when using `adt` with mixins, see #1457

# 0.18.16

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package smithy4s.example


trait HasName {
def name: Option[String]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package smithy4s.example

import smithy4s.Hints
import smithy4s.Schema
import smithy4s.ShapeId
import smithy4s.ShapeTag
import smithy4s.schema.Schema.string
import smithy4s.schema.Schema.struct
import smithy4s.schema.Schema.union

sealed trait PersonUnion extends scala.Product with scala.Serializable { self =>
@inline final def widen: PersonUnion = this
def $ordinal: Int

object project {
def p: Option[PersonUnion.OtherPerson] = PersonUnion.OtherPerson.alt.project.lift(self)
}

def accept[A](visitor: PersonUnion.Visitor[A]): A = this match {
case value: PersonUnion.OtherPerson => visitor.p(value)
}
}
object PersonUnion extends ShapeTag.Companion[PersonUnion] {

def otherPerson(name: String):OtherPerson = OtherPerson(name)

val id: ShapeId = ShapeId("smithy4s.example", "PersonUnion")

val hints: Hints = Hints.empty

final case class OtherPerson(name: String) extends PersonUnion {
def $ordinal: Int = 0
}

object OtherPerson extends ShapeTag.Companion[OtherPerson] {
val id: ShapeId = ShapeId("smithy4s.example", "OtherPerson")

val hints: Hints = Hints.empty

// constructor using the original order from the spec
private def make(name: String): OtherPerson = OtherPerson(name)

val schema: Schema[OtherPerson] = struct(
string.required[OtherPerson]("name", _.name),
)(make).withId(id).addHints(hints)

val alt = schema.oneOf[PersonUnion]("p")
}


trait Visitor[A] {
def p(value: PersonUnion.OtherPerson): A
}

object Visitor {
trait Default[A] extends Visitor[A] {
def default: A
def p(value: PersonUnion.OtherPerson): A = default
}
}

implicit val schema: Schema[PersonUnion] = union(
PersonUnion.OtherPerson.alt,
){
_.$ordinal
}.withId(id).addHints(hints)
}
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,11 @@ private[codegen] class SmithyToIR(model: Model, namespace: String) {
.asScala
.toList
.map(mem => model.expectShape(mem.getTarget))
val mixins = memberTargets
.map(_.getMixins.asScala.toSet)
val mixins: List[Set[ShapeId]] = memberTargets
.map(targetShape =>
targetShape.getMixins.asScala.toSet
.filter(mixinId => doFieldsMatch(mixinId, targetShape.fields))
)

val union = mixins.foldLeft(Set.empty[ShapeId])(_ union _)

Expand Down
16 changes: 16 additions & 0 deletions sampleSpecs/adtMember.smithy
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,19 @@ structure PodcastCommon {
structure Video with [PodcastCommon] {}
@generateOptics
structure Audio with [PodcastCommon] {}


@mixin
structure HasName {
name: String
}

structure OtherPerson with [HasName] {
@required
$name
}

@adt
union PersonUnion {
p: OtherPerson
}

0 comments on commit 5480e8e

Please sign in to comment.