diff --git a/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Narrow.scala b/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Narrow.scala index f0d5e24..a343e5e 100644 --- a/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Narrow.scala +++ b/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Narrow.scala @@ -475,6 +475,8 @@ class Narrow(pipelineContext: PipelineContext) { BoundedDynamicType(adjustMapType(bound, keyT, valT)) case shapeMap: ShapeMap => adjustShapeMap(shapeMap, keyT, valT) + case DictMap(kT, vT) if subtype.isDynamicType(kT) && subtype.isDynamicType(vT) => + DictMap(kT, vT) case dictMap: DictMap => adjustDictMap(dictMap, keyT, valT) case UnionType(elems) => diff --git a/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Subtype.scala b/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Subtype.scala index 665f44b..2112633 100644 --- a/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Subtype.scala +++ b/eqwalizer/src/main/scala/com/whatsapp/eqwalizer/tc/Subtype.scala @@ -199,13 +199,12 @@ class Subtype(pipelineContext: PipelineContext) { if (!subTypePol(t1, t2, seen)) return false } true - case (DictMap(kT, vT), ShapeMap(_)) if isDynamicType(kT) && isDynamicType(vT) => - true case (DictMap(kT, vT), ShapeMap(props)) => val (reqProps, optProps) = props.partition { case ReqProp(_, _) => true case OptProp(_, _) => false } + if (isDynamicType(kT) && isDynamicType(vT) && v1 == -) return true if (reqProps.nonEmpty) return false val shapeDomain = join(optProps.map(prop => AtomLitType(prop.key))) subTypePol(kT, shapeDomain, seen) && props.forall(prop => subTypePol(vT, prop.tp, seen)) diff --git a/eqwalizer/test_projects/check_gradual/src/gradual_complex_types.erl.check b/eqwalizer/test_projects/check_gradual/src/gradual_complex_types.erl.check index 4899642..8ea3d38 100644 --- a/eqwalizer/test_projects/check_gradual/src/gradual_complex_types.erl.check +++ b/eqwalizer/test_projects/check_gradual/src/gradual_complex_types.erl.check @@ -124,7 +124,7 @@ generic(_, _) -> error(stub). | OK | (dyn_map(), #{a => atom()}) -> ok. | | use_generic_shape(DM, S) -> | ERROR | generic(DM, S). | | generic(DM, S). - | | Expression has type: #S{a => atom()} + | | Expression has type: dyn_map() | #S{a => atom()} | | Context expected type: 'ok' | | -spec tuple_mismatch(dyn_map()) -> | | diff --git a/eqwalizer/test_projects/fault_tolerance/src/fault_tolerance.erl.check b/eqwalizer/test_projects/fault_tolerance/src/fault_tolerance.erl.check index 7c6b476..5d31770 100644 --- a/eqwalizer/test_projects/fault_tolerance/src/fault_tolerance.erl.check +++ b/eqwalizer/test_projects/fault_tolerance/src/fault_tolerance.erl.check @@ -369,11 +369,11 @@ maps(M) -> | ERROR | | | Expression has type: 'b' | | Context expected type: number() M1 + M2. | | M1. - | | Expression has type: #D{dynamic() | 'id' => dynamic() | number()} + | | Expression has type: #D{dynamic() => dynamic()} | | Context expected type: number() | | --- | | M2. - | | Expression has type: #D{dynamic() | 'id' => dynamic() | number()} + | | Expression has type: #D{dynamic() => dynamic()} | | Context expected type: number() | | --- | | _ + _. diff --git a/eqwalizer/test_projects/fault_tolerance/src/fault_tolerance.erl.json b/eqwalizer/test_projects/fault_tolerance/src/fault_tolerance.erl.json index 19ba5f3..82dc981 100644 --- a/eqwalizer/test_projects/fault_tolerance/src/fault_tolerance.erl.json +++ b/eqwalizer/test_projects/fault_tolerance/src/fault_tolerance.erl.json @@ -3623,7 +3623,7 @@ "end": 3252 }, "lineAndCol": null, - "message": "Expression has type: #D{dynamic() | 'id' => dynamic() | number()}\nContext expected type: number()", + "message": "Expression has type: #D{dynamic() => dynamic()}\nContext expected type: number()", "uri": "https://fb.me/eqwalizer_errors#incompatible_types", "code": "incompatible_types", "expressionOrNull": "M1", @@ -3652,39 +3652,21 @@ "got": { "DictMap": { "k_type": { - "UnionType": { - "tys": [ - { - "RemoteType": { - "id": { - "module": "eqwalizer", - "name": "dynamic", - "arity": 0 - } - } - }, - { - "AtomLitType": { - "atom": "id" - } - } - ] + "RemoteType": { + "id": { + "module": "eqwalizer", + "name": "dynamic", + "arity": 0 + } } }, "v_type": { - "UnionType": { - "tys": [ - { - "RemoteType": { - "id": { - "module": "eqwalizer", - "name": "dynamic", - "arity": 0 - } - } - }, - "NumberType" - ] + "RemoteType": { + "id": { + "module": "eqwalizer", + "name": "dynamic", + "arity": 0 + } } } } @@ -3778,7 +3760,7 @@ "end": 3257 }, "lineAndCol": null, - "message": "Expression has type: #D{dynamic() | 'id' => dynamic() | number()}\nContext expected type: number()", + "message": "Expression has type: #D{dynamic() => dynamic()}\nContext expected type: number()", "uri": "https://fb.me/eqwalizer_errors#incompatible_types", "code": "incompatible_types", "expressionOrNull": "M2", @@ -3807,39 +3789,21 @@ "got": { "DictMap": { "k_type": { - "UnionType": { - "tys": [ - { - "RemoteType": { - "id": { - "module": "eqwalizer", - "name": "dynamic", - "arity": 0 - } - } - }, - { - "AtomLitType": { - "atom": "id" - } - } - ] + "RemoteType": { + "id": { + "module": "eqwalizer", + "name": "dynamic", + "arity": 0 + } } }, "v_type": { - "UnionType": { - "tys": [ - { - "RemoteType": { - "id": { - "module": "eqwalizer", - "name": "dynamic", - "arity": 0 - } - } - }, - "NumberType" - ] + "RemoteType": { + "id": { + "module": "eqwalizer", + "name": "dynamic", + "arity": 0 + } } } }