diff --git a/packages/freezed/lib/src/templates/abstract_template.dart b/packages/freezed/lib/src/templates/abstract_template.dart index 32a27411..a4a8148a 100644 --- a/packages/freezed/lib/src/templates/abstract_template.dart +++ b/packages/freezed/lib/src/templates/abstract_template.dart @@ -46,7 +46,8 @@ mixin _\$${data.name.public}${data.genericsDefinitionTemplate}$interfaces { $abstractProperties ${copyWith?.copyWithGetter(needsCast: true) ?? ''} -${methods(data, globalData, properties: commonProperties, name: data.name, escapedName: data.escapedName, source: Source.mixin)} +// Fixed: Added isConst parameter for hashCode caching +${methods(data, globalData, properties: commonProperties, name: data.name, escapedName: data.escapedName, source: Source.mixin, isConst: false)} } ${copyWith?.commonInterface ?? ''} diff --git a/packages/freezed/lib/src/templates/concrete_template.dart b/packages/freezed/lib/src/templates/concrete_template.dart index 19271f4a..8405350f 100644 --- a/packages/freezed/lib/src/templates/concrete_template.dart +++ b/packages/freezed/lib/src/templates/concrete_template.dart @@ -50,7 +50,7 @@ class ${constructor.redirectedName}${data.genericsDefinitionTemplate} $_concrete $_properties ${copyWith?.copyWithGetter(needsCast: false) ?? ''} -${methods(data, globalData, properties: constructor.properties, name: constructor.redirectedName, escapedName: constructor.escapedName, source: Source.syntheticClass)} +${methods(data, globalData, properties: constructor.properties, name: constructor.redirectedName, escapedName: constructor.escapedName, source: Source.syntheticClass, isConst: constructor.isConst)} } ${copyWith?.interface ?? ''} @@ -325,12 +325,13 @@ String methods( required String name, required String escapedName, required Source source, + required bool isConst, }) { return ''' ${toJson(data, name: name, source: source)} ${debugFillProperties(data, globalData, properties, escapedClassName: escapedName)} ${operatorEqualMethod(data, properties, className: name, source: source)} -${hashCodeMethod(data, properties, source: source)} +${hashCodeMethod(data, properties, source: source, isConst: isConst)} ${toStringMethod(data, globalData, escapedClassName: escapedName, properties: properties)} '''; } @@ -467,6 +468,7 @@ String hashCodeMethod( Class data, List properties, { required Source source, + required bool isConst, }) { if (!data.options.equal) return ''; @@ -491,25 +493,25 @@ String hashCodeMethod( property.name, ]; - if (hashedProperties.length == 1) { + final hashCodeExpression = hashedProperties.length == 1 + ? '${hashedProperties.first}.hashCode' + : hashedProperties.length >= 20 + ? 'Object.hashAll([${hashedProperties.join(',')}])' + : 'Object.hash(${hashedProperties.join(',')})'; + + if (isConst || source == Source.mixin) { return ''' $jsonKey @override -int get hashCode => ${hashedProperties.first}.hashCode; -'''; - } - if (hashedProperties.length >= 20) { - return ''' -$jsonKey -@override -int get hashCode => Object.hashAll([${hashedProperties.join(',')}]); +int get hashCode => $hashCodeExpression; '''; } return ''' $jsonKey +int? _cachedHashCode; @override -int get hashCode => Object.hash(${hashedProperties.join(',')}); +int get hashCode => _cachedHashCode ??= $hashCodeExpression; '''; } diff --git a/packages/freezed_annotation/lib/freezed_annotation.dart b/packages/freezed_annotation/lib/freezed_annotation.dart index 9a5f4631..a7733f0f 100644 --- a/packages/freezed_annotation/lib/freezed_annotation.dart +++ b/packages/freezed_annotation/lib/freezed_annotation.dart @@ -18,11 +18,11 @@ class EqualUnmodifiableListView extends UnmodifiableListView { bool operator ==(Object other) { return other is EqualUnmodifiableListView && other.runtimeType == runtimeType && - other._source == _source; + const DeepCollectionEquality().equals(other._source, _source); } @override - int get hashCode => Object.hash(runtimeType, _source); + int get hashCode => Object.hash(runtimeType, const DeepCollectionEquality().hash(_source)); } /// An [UnmodifiableSetView] which overrides == @@ -36,11 +36,11 @@ class EqualUnmodifiableSetView extends UnmodifiableSetView { bool operator ==(Object other) { return other is EqualUnmodifiableSetView && other.runtimeType == runtimeType && - other._source == _source; + const DeepCollectionEquality().equals(other._source, _source); } @override - int get hashCode => Object.hash(runtimeType, _source); + int get hashCode => Object.hash(runtimeType, const DeepCollectionEquality().hash(_source)); } /// An [UnmodifiableMapView] which overrides == @@ -55,11 +55,11 @@ class EqualUnmodifiableMapView bool operator ==(Object other) { return other is EqualUnmodifiableMapView && other.runtimeType == runtimeType && - other._source == _source; + const DeepCollectionEquality().equals(other._source, _source); } @override - int get hashCode => Object.hash(runtimeType, _source); + int get hashCode => Object.hash(runtimeType, const DeepCollectionEquality().hash(_source)); } /// Options for enabling/disabling specific `Union.map` features;