Currently, canImport only supports checking for top-level module availability while many have submodules with different availability. For example, while CIFilter was introduced in iOS 5, CIFilterBuiltins is only available on iOS 13+. Therefore, one might want to write code like this:
My pull request extends canImport to check for submodule availability (and submodule availability only). According to the original proposal SE-0075,
#if canImport(module-name) tests for module support by name.
The question of "is this a proposal or a bug fix" comes down to the interpretation of "module name". Here are some facts:
The original review / discussion never mentioned anything about submodules
The Swift Programming Language reference specifies that module-name → identifier (likely based on the original implementation), but extending canImport to check for submodules means the syntax will need to be updated to module-name → import-path.
Do you all think this is just a simple bug fix, or is this something that has go through Swift evolution?
Why I don't think renaming to canImportModule is a good idea:
If we decide to support checking for availability of types and rename canImport to canImportModule, I would assume we would similarly introduce canImportClass, canImportStruct, canImportEnum, etc., analogous to import class, import struct, import enum, etc..
Actually, the current implementation does not emit any diagnostics if a type name is given. I might update my PR to emit a warning if no such submodule if found, but a matching type is.
Now I'm a little reluctant to add the warning because, not only do we have to load the module to implement this (while currently we don't have to, nor do we want to), but also, for a hypothetical situation where there (somehow) exists 3 valid versions of module A:
module A with neither submodule B nor type B
module A with submodule B
module A with type B
would we expect case 3 to behave just like case 1 for this piece of code, or should we emit an additional warning?
#if canImport(A.B)
...
#else
...
#endif
To me, emitting a warning in this case seems to be a false positive, and there's no way of silencing it (unlike "nearly matches protocol requirement").
Since we are on the subject of diagnostics, I do NOT think this existing test should produce a compile time error as it's doing now:
If you wanted to support types instead of just submodules, I think it would make the most sense to align with existing import syntax:
#if canImport(A.B) // only checks for submodule A.B
import A.B
#endif
#if canImport(class A.B) // only checks for class B in module A
import class A.B
#endif
However, I don't know if there are any additional concerns about checking for types, since it would involve loading the whole module/submodule anyway in order to determine whether or not the module exists, whereas (I believe? I could be wrong) checking canImport for a module doesn't actually require loading it, just verifying that it exists on the search path.
IMO (I speak with no authority here), I think the most sensible approach going forward would be to extend canImport(...) to handle submodules only, and leave support for types as a separate problem to be solved later.
Personally, I would consider this to be a bug fix. Import allows submodules, and so it's completely reasonable for canImport to be able to check for submodules.