# Surprisingly permissive compilation

**URL:** <https://forums.swift.org/t/surprisingly-permissive-compilation/51020>\
**Category:** Using Swift\
**Created:** [August 7, 2021, 1:08pm UTC](https://forums.swift.org/t/surprisingly-permissive-compilation/51020 "2021-08-07T13:08:39Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![GreatApe](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/greatape/32/2640_2.png) [@GreatApe](https://forums.swift.org/u/GreatApe)\
**Post date:** [August 7, 2021, 1:08pm UTC](https://forums.swift.org/t/surprisingly-permissive-compilation/51020/1 "2021-08-07T13:08:39Z")

</div>

The compiler behaves a bit strange here, maybe I'm missing something?

Consider an inner generic type, with a constraint on the type:

```swift
struct MyInnerType<T: Error> {
    let t: T
}

```

I don't have to worry about this constraint here, presumably the compiler figures that you won't be able to construct a value with the wrong T anyway. This makes sense.

```swift
struct MyOuterType1 {
    func test<T>(_ value: MyInnerType<T>) { }
}

```

This is perhaps a bit less obvious, but it works in practice because you need to constrain it manually:

```swift
struct MyOuterType1b {
    func test<T>() -> MyInnerType<T> { fatalError() }
}

```

This also works because the entire outer type is constrained w.r.t T

```swift
struct MyOuterType2<T: Error> {
    func test() -> MyInnerType<T> { fatalError() }
}

```

This rightly fails, because the outer type could have anything as `T`, and _it_ is "in control" of `T`

```swift
struct MyOuterType3<T> {
    // T does not conform to Error
    func test() -> MyInnerType<T> { fatalError() }
}

```

So why does this work? `T` is constrained, but not to `Error`.

```swift
struct MyOuterType4<T> {
    func test() -> MyInnerType<T> where T: Collection { fatalError() }
}

```

That function looks like it's available for any `T` that is a `Collection`, but in reality `T` will have to be both a `Collection` and an `Error`:

```swift
enum MyEnum { case one }
enum MyError: Error { case one }
extension Array: Error where Element: Error { }

func ttt() {
    // Collection and Error -> OK
    MyOuterType4<[MyError]>().test() 

    // Only Collection -> Referencing instance method 'test()' on 'Array' requires that 'Double' conform to 'Error'
    MyOuterType4<[Double]>().test()

    // Only Error -> Instance method 'test()' requires that 'MyError' conform to 'Collection'
    MyOuterType4<MyError>().test()

    // Neither -> Compiler shows both of the errors
    MyOuterType4<MyEnum>().test()
}

```

When the constraint is on the type though, it has to be the correct one:

```swift
struct MyOuterType4<T: Collection> { 
    // Type 'T' does not conform to protocol 'Error'
    func test(_ value: MyInnerType<T>) { }
}

```

This is not necessarily a bug, but I wonder if there's an explanation for the behaviour?

---

<div class="post-metadata">

**Author:** ![Saklad5](https://avatars.discourse-cdn.com/v4/letter/s/4491bb/32.png) [@Saklad5](https://forums.swift.org/u/Saklad5)\
**Post date:** [August 7, 2021, 7:56pm UTC](https://forums.swift.org/t/surprisingly-permissive-compilation/51020/2 "2021-08-07T19:56:36Z")

</div>

`MyOuterType4.T` can be _anything_ conforming to `Collection`.

`MyInnerType.T` can be _anything_ conforming to `Error`.

```swift
struct MyOuterType4<T> {
    func test() -> MyInnerType<T> where T: Collection { fatalError() }
}

```

You already constrained `MyInnerType.T` to `Error`, so you do not need to repeat that. By adding the conditional constraint to `Collection`, you are effectively ending up with `T: Error & Collection`.

As for the compiler errors: Swift tries to make errors as relevant as possible by providing the conformance requirements the type is closest to meeting. Since you provided a conditional conformance to `Error` for `Array`, but don’t meet the conditions, that’s what it shows. `Array` _does_ conform to `Collection`, after all.

Does that make sense?

---

<div class="post-metadata">

**Author:** ![GreatApe](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/greatape/32/2640_2.png) [@GreatApe](https://forums.swift.org/u/GreatApe)\
**Post date:** [August 7, 2021, 8:24pm UTC](https://forums.swift.org/t/surprisingly-permissive-compilation/51020/3 "2021-08-07T20:24:28Z")

</div>

Maybe I was unclear, I am not surprised at `MyOuterType4`, it follows the logic you - and I - described, that the constraint inherent in `MyInnerType` will constrain the function. Further constraining it is orthogonal. But my point is that with that logic, `MyOuterType3` should also be fine.

It seems that the mere act of adding a `where` clause, _any_ `where` clause, makes the compiler remember that `MyInnerType` has a constraint, and applies it. Without the where clause, it doesn't.

So:

Why do `MyOuterType1`, `MyOuterType1b` and `MyOuterType4` work, but not `MyOuterType3`?

Edit:  
Inner -\> Outer

---

<div class="post-metadata">

**Author:** ![Saklad5](https://avatars.discourse-cdn.com/v4/letter/s/4491bb/32.png) [@Saklad5](https://forums.swift.org/u/Saklad5)\
**Post date:** [August 7, 2021, 8:43pm UTC](https://forums.swift.org/t/surprisingly-permissive-compilation/51020/4 "2021-08-07T20:43:15Z")

</div>

I’m assuming you mean `MyOuterType3`.

Now that you mention it, I think that _is_ a bug. It seems like the compiler makes `Error` conformance conditional if there are other conditions, even though those conditions do not include `Error`.

---

<div class="post-metadata">

**Author:** ![typesanitizer](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/typesanitizer/32/8661_2.png) [@typesanitizer](https://forums.swift.org/u/typesanitizer)\
**Post date:** [August 8, 2021, 5:16am UTC](https://forums.swift.org/t/surprisingly-permissive-compilation/51020/5 "2021-08-08T05:16:19Z")

</div>

cc @Slava_Pestov

---

<div class="post-metadata">

**Author:** ![Slava\_Pestov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slava_pestov/32/30204_2.png) [@Slava\_Pestov](https://forums.swift.org/u/Slava_Pestov)\
**Post date:** [August 11, 2021, 2:47am UTC](https://forums.swift.org/t/surprisingly-permissive-compilation/51020/6 "2021-08-11T02:47:39Z")

</div>

In a generic declaration, the "T : Error" requirement on a generic parameter "T" is inferred from the appearance of T in the "MyInnerType" type constructor, however this inference only runs if the declaration has generic parameters _or_ a where clause. If it has neither, the inference step is not performed, and "T : Error" must be explicitly stated in an outer generic signature.
