Preserve generics on static member variables translated to class properties. - #2815
Open
copybara-service[bot] wants to merge 1 commit into
Open
Preserve generics on static member variables translated to class properties.#2815copybara-service[bot] wants to merge 1 commit into
copybara-service[bot] wants to merge 1 commit into
Conversation
copybara-service
Bot
force-pushed
the
test_952947498
branch
14 times, most recently
from
July 24, 2026 07:25
441ab7c to
aff4f00
Compare
…erties. J2ObjC was not preserving generic type information when translating static member variables to Objective-C class properties. This change updates PropertyGenerator to use the generic type declaration if generics are enabled. Also updates HeaderImportCollector to collect generic parameters for fields, ensuring they are forward declared or imported in the generated headers when generics are enabled. Generic parameters that are JRE types (e.g. java.lang.Boolean) are explicitly imported (#include) in the header instead of forward declared (@Class) to avoid Swift compiler errors (incomplete interface) when importing properties using these generic parameters. To prevent circular dependency cycles when compiling the JRE emulation library (jre_emul) itself, HeaderImportCollector checks if the current compilation unit belongs to a core JRE package (java.*, and selected javax.*, android.*, org.* packages that are part of jre_emul). If so, it bypasses the JRE force-import logic and falls back to default forward declarations for all generic parameters. This core JRE check specifically excludes packages like javax.inject (jsr330) which are not part of jre_emul, preventing dependency violations in modular builds where headers would otherwise try to directly import javax/inject/Provider.h without the target declaring a direct dependency on the jsr330 module. To resolve Objective-C compilation errors (incompatible pointer types) when passing generic arguments to generic methods (which are erased to bounds in ObjC, e.g. DXLTextProtocolNestedNestedModelType<id<DXLModelModel>> * expected but DXLTextProtocolNestedNestedModelType<DXLVotingModelVotingChip *> * provided), this change makes all Objective-C lightweight generics covariant by prepending `__covariant` to generic type parameters in generated class declarations and extensions (TypeDeclarationGenerator and TypePrivateDeclarationGenerator). This matches Java's type safety checks which were already performed by javac, and allows implicit conversions (e.g., from Generic<SubClass *> * to Generic<id<Protocol>> * or Generic<id> *) in ObjC that would otherwise be rejected by strict invariant pointer checks. To resolve similar pointer mismatch errors when assigning erased generic method returns (e.g. SettingKey<MessageLite> returned by generic factory method) to specific generic static fields (e.g. SettingKey<ActiveExperimentIds>), this change updates CastResolver to perform a stricter assignability check that considers ObjC generic type parameters when options.asObjCGenericDecl() is enabled. If the generic parameters do not match (taking covariance into account), CastResolver will now correctly insert a cast in the ObjC translation (which is generated as a raw class pointer cast, e.g. `(SettingKey *)`, sufficient to satisfy the ObjC compiler). Note on C function signatures: J2ObjC generated C functions (representing static methods and constructors) must remain erased (no ObjC generics) in their signatures. This is because C functions are global and do not have access to class-level or method-level generic type variables, and trying to use them (e.g. `JavaLangEnum<E> *`) would trigger ObjC compiler errors. Furthermore, enabling generics for C functions causes Swift compilation errors (generic argument mismatch) when passing these typed J2ObjC generics to native ObjC APIs that expect raw types (imported as `<AnyObject>` in Swift). Thus, C function signatures are kept raw, and tests are added to verify this erasure behavior. Also updates TypeGenerator, TypeDeclarationGenerator, and TypeImplementationGenerator to support generic types in C-style accessors and global variable declarations for static fields (the default translation when class properties are disabled). Generics support in TypeGenerator.getDeclarationType is restricted to static fields only, to avoid generating generic types for instance fields which can trigger ObjC compiler errors (incompatible pointer types) on generic method return assignments due to J2ObjC missing casts for ObjC generics. To support generic types with multiple parameters (which contain commas) in C preprocessor macros (like J2OBJC_STATIC_FIELD_OBJ), TypeDeclarationGenerator now generates a typedef for these types in the header and uses the typedef name in the macro call and accessor declarations, avoiding macro argument parsing errors. Adds test cases for: - Automatic class properties (setClassProperties=true). - Automatic class properties with @GenerateObjectiveCGenerics. - Explicit class properties via @Property. - Default static field translation (both options false) to verify C-style accessors and global variables are used, and they correctly preserve generics when enabled. - Default static field translation with multiple generic parameters (containing commas) to verify the typedef workaround. - HeaderImportCollector JRE generic parameters import behavior. - CastResolver generic method assignment cast behavior. - C function signatures for static methods being erased (no generics). - C function signatures for constructors being erased (no generics). Updates existing GenerateObjectiveCGenericsTest cases to expect `__covariant` in generated class declarations and extensions. PiperOrigin-RevId: 952947498
copybara-service
Bot
force-pushed
the
test_952947498
branch
from
July 24, 2026 08:48
aff4f00 to
ae3b436
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Preserve generics on static member variables translated to class properties.
J2ObjC was not preserving generic type information when translating static member variables to Objective-C class properties. This change updates PropertyGenerator to use the generic type declaration if generics are enabled.
Also updates HeaderImportCollector to collect generic parameters for fields, ensuring they are forward declared or imported in the generated headers when generics are enabled.
Generic parameters that are JRE types (e.g. java.lang.Boolean) are explicitly imported (#include) in the header instead of forward declared (@Class) to avoid Swift compiler errors (incomplete interface) when importing properties using these generic parameters.
To prevent circular dependency cycles when compiling the JRE emulation library (jre_emul) itself, HeaderImportCollector checks if the current compilation unit belongs to a core JRE package (java., and selected javax., android., org. packages that are part of jre_emul). If so, it bypasses the JRE force-import logic and falls back to default forward declarations for all generic parameters.
This core JRE check specifically excludes packages like javax.inject (jsr330) which are not part of jre_emul, preventing dependency violations in modular builds where headers would otherwise try to directly import javax/inject/Provider.h without the target declaring a direct dependency on the jsr330 module.
To resolve Objective-C compilation errors (incompatible pointer types) when passing generic arguments to generic methods (which are erased to bounds in ObjC, e.g. DXLTextProtocolNestedNestedModelType<id> * expected but DXLTextProtocolNestedNestedModelType<DXLVotingModelVotingChip *> * provided), this change makes all Objective-C lightweight generics covariant by prepending
__covariantto generic type parameters in generated class declarations and extensions (TypeDeclarationGenerator and TypePrivateDeclarationGenerator).This matches Java's type safety checks which were already performed by javac, and allows implicit conversions (e.g., from Generic<SubClass *> * to Generic<id> * or Generic *) in ObjC that would otherwise be rejected by strict invariant pointer checks.
To resolve similar pointer mismatch errors when assigning erased generic method returns (e.g. SettingKey returned by generic factory method) to specific generic static fields (e.g. SettingKey), this change updates CastResolver to perform a stricter assignability check that considers ObjC generic type parameters when options.asObjCGenericDecl() is enabled.
If the generic parameters do not match (taking covariance into account), CastResolver will now correctly insert a cast in the ObjC translation (which is generated as a raw class pointer cast, e.g.
(SettingKey *), sufficient to satisfy the ObjC compiler).Note on C function signatures: J2ObjC generated C functions (representing static methods and constructors) must remain erased (no ObjC generics) in their signatures. This is because C functions are global and do not have access to class-level or method-level generic type variables, and trying to use them (e.g.
JavaLangEnum<E> *) would trigger ObjC compiler errors. Furthermore, enabling generics for C functions causes Swift compilation errors (generic argument mismatch) when passing these typed J2ObjC generics to native ObjC APIs that expect raw types (imported as<AnyObject>in Swift). Thus, C function signatures are kept raw, and tests are added to verify this erasure behavior.Also updates TypeGenerator, TypeDeclarationGenerator, and TypeImplementationGenerator to support generic types in C-style accessors and global variable declarations for static fields (the default translation when class properties are disabled).
Generics support in TypeGenerator.getDeclarationType is restricted to static fields only, to avoid generating generic types for instance fields which can trigger ObjC compiler errors (incompatible pointer types) on generic method return assignments due to J2ObjC missing casts for ObjC generics.
To support generic types with multiple parameters (which contain commas) in C preprocessor macros (like J2OBJC_STATIC_FIELD_OBJ), TypeDeclarationGenerator now generates a typedef for these types in the header and uses the typedef name in the macro call and accessor declarations, avoiding macro argument parsing errors.
Adds test cases for:
Updates existing GenerateObjectiveCGenericsTest cases to expect
__covariantin generated class declarations and extensions.