I believe the place that's *supposed* to catch this is the downcast: `A<Int where Int: P via M1>`

and `A<Int where Int: P via M2>`

are intended to be distinct types, even though that's not visible in the user-visible syntax. You can see this in the expanded mangled names for `makeA`

in each module if you try to return the concrete `A<Int>`

instead of `Any`

:

```
% xcrun swift-demangle -expand s2M15makeA2M01AVyS2iAC1PAAyHCg_GyF
Demangling for $s2M15makeA2M01AVyS2iAC1PAAyHCg_GyF
kind=Global
kind=Function
kind=Module, text="M1"
kind=Identifier, text="makeA"
kind=Type
kind=FunctionType
kind=ArgumentTuple
kind=Type
kind=Tuple
kind=ReturnType
kind=Type
kind=BoundGenericStructure
kind=Type
kind=Structure
kind=Module, text="M0"
kind=Identifier, text="A"
kind=TypeList
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=TypeList
kind=RetroactiveConformance
kind=Number, index=0
kind=ConcreteProtocolConformance
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=ProtocolConformanceRefInOtherModule
kind=Type
kind=Protocol
kind=Module, text="M0"
kind=Identifier, text="P"
kind=Module, text="M1"
kind=AnyProtocolConformanceList
$s2M15makeA2M01AVyS2iAC1PAAyHCg_GyF ---> M1.makeA() -> M0.A<Swift.Int>
```

```
% xcrun swift-demangle -expand s2M25makeA2M01AVyS2iAC1PAAyHCg_GyF
Demangling for $s2M25makeA2M01AVyS2iAC1PAAyHCg_GyF
kind=Global
kind=Function
kind=Module, text="M2"
kind=Identifier, text="makeA"
kind=Type
kind=FunctionType
kind=ArgumentTuple
kind=Type
kind=Tuple
kind=ReturnType
kind=Type
kind=BoundGenericStructure
kind=Type
kind=Structure
kind=Module, text="M0"
kind=Identifier, text="A"
kind=TypeList
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=TypeList
kind=RetroactiveConformance
kind=Number, index=0
kind=ConcreteProtocolConformance
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=ProtocolConformanceRefInOtherModule
kind=Type
kind=Protocol
kind=Module, text="M0"
kind=Identifier, text="P"
kind=Module, text="M2"
kind=AnyProtocolConformanceList
$s2M25makeA2M01AVyS2iAC1PAAyHCg_GyF ---> M2.makeA() -> M0.A<Swift.Int>
```

(specifically, notice the ProtocolConformanceRefInOtherModule a few lines from the end in each expansion)

The Any sidesteps the link error by keeping the *real* fully-qualified name of `A<Int>`

out of the signature. But that means the `as!`

likewise should have a fully-qualified `A<Int via M1>`

or `A<Int via M2>`

that it's targeting (when I compile your example I get `true`

and `false`

in the printout, so I guess it picked M1), and the runtime should take that into account when it does a downcast. Even though it might make downcasts slower.

That said, in the concrete case this ought to also be detectable at compile time rather than link time: if the swiftmodule files for M1 and M2 recorded which conformance was used, M3 would be able to tell that the types don't match.

I don't know/remember if it's possible for the uses in M1 and M2 to *actually* get mixed up due to runtime caching of what `A<Int>`

is, or which conformance to use for `Int: P`

, but *in the model* I believe the only thing that does *global* lookups of conformances is downcasts to protocol types (`any`

types). To actually support that model well we'd need a way to communicate `A<Int where Int: P via M1>`

to users, though, and possibly even a way to spell it in source. @Joe_Groff has talked about explicitly supporting that before (presumably much like your scoped conformances), but as far as I know very little work has actually been done in that direction.