diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart index 67247fd1483..4b3243dcbe7 100644 --- a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart +++ b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart @@ -10925,30 +10925,45 @@ class InferenceVisitorImpl extends InferenceVisitorBase }) { DartType requiredType = pattern.requiredType; if (!pattern.hasExplicitTypeArguments) { - if (pattern.typedef != null) { - // TODO(paulberry): handle typedefs properly. - } - if (requiredType is InterfaceType && - requiredType.classNode.typeParameters.isNotEmpty) { + Typedef? typedef = pattern.typedef; + if (typedef != null) { + List typedefTypeParameters = typedef.typeParameters; + if (typedefTypeParameters.isNotEmpty) { + List asTypeArguments = + getAsTypeArguments(typedefTypeParameters, libraryBuilder.library); + TypedefType typedefType = new TypedefType( + typedef, libraryBuilder.library.nonNullable, asTypeArguments); + DartType unaliasedTypedef = typedefType.unalias; + List inferredTypeArguments = _inferTypeArguments( + typeParameters: typedefTypeParameters, + declaredType: unaliasedTypedef, + contextType: matchedType); + requiredType = new TypedefType(typedef, + libraryBuilder.library.nonNullable, inferredTypeArguments) + .unalias; + } + } else if (requiredType is InterfaceType) { List typeParameters = requiredType.classNode.typeParameters; + if (typeParameters.isNotEmpty) { + // It's possible that one of the callee type parameters might match a + // type that already exists as part of inference. This might happen, + // for instance, in the case where a method in a generic class + // contains an object pattern naming the enclosing class. To avoid + // creating invalid inference results, we need to create fresh type + // parameters. + FreshTypeParameters fresh = getFreshTypeParameters(typeParameters); + InterfaceType declaredType = new InterfaceType(requiredType.classNode, + requiredType.declaredNullability, fresh.freshTypeArguments); + typeParameters = fresh.freshTypeParameters; - // It's possible that one of the callee type parameters might match a - // type that already exists as part of inference. This might happen, - // for instance, in the case where a method in a generic class contains - // an object pattern naming the enclosing class. To avoid creating - // invalid inference results, we need to create fresh type parameters. - FreshTypeParameters fresh = getFreshTypeParameters(typeParameters); - InterfaceType declaredType = new InterfaceType(requiredType.classNode, - requiredType.declaredNullability, fresh.freshTypeArguments); - typeParameters = fresh.freshTypeParameters; - - List inferredTypeArguments = _inferTypeArguments( - typeParameters: typeParameters, - declaredType: declaredType, - contextType: matchedType); - requiredType = new InterfaceType(requiredType.classNode, - requiredType.declaredNullability, inferredTypeArguments); + List inferredTypeArguments = _inferTypeArguments( + typeParameters: typeParameters, + declaredType: declaredType, + contextType: matchedType); + requiredType = new InterfaceType(requiredType.classNode, + requiredType.declaredNullability, inferredTypeArguments); + } } } return requiredType; diff --git a/tests/language/patterns/object_pattern_inference_test.dart b/tests/language/patterns/object_pattern_inference_test.dart index 745ca1731dd..ea1ed13e722 100644 --- a/tests/language/patterns/object_pattern_inference_test.dart +++ b/tests/language/patterns/object_pattern_inference_test.dart @@ -44,14 +44,15 @@ bool simpleInference(B b) { // No need for a `return` since the switch is exhaustive. } -void inferDynamic(Object o) { +bool inferDynamic(Object o) { switch (o) { case C(listOfT: var x, t: var t): x.expectStaticType>>(); t.isEven; // Should be ok since T is `dynamic`. o.expectStaticType>>(); + return true; default: - Expect.fail('Match failure'); + return false; } } @@ -66,13 +67,14 @@ class D { D(this.t); } -void inferBound(Object o) { +bool inferBound(Object o) { switch (o) { case D(listOfT: var x): x.expectStaticType>>(); o.expectStaticType>>(); + return true; default: - Expect.fail('Match failure'); + return false; } } @@ -110,13 +112,14 @@ class F2 extends F1 { } } -void fBounded(Object o) { +bool fBounded(Object o) { switch (o) { case F1(listOfT: var x): x.expectStaticType>>>(); o.expectStaticType>>>(); + return true; default: - Expect.fail('Match failure'); + return false; } } @@ -136,22 +139,71 @@ class G2> extends G1 { G2(super.t, this.u); } -void partialInference(G1 g) { +bool partialInference(G1 g) { switch (g) { case G2(listOfT: var x, listOfU: var y): x.expectStaticType>>(); y.expectStaticType>>>(); g.expectStaticType>>>(); + return true; + default: + return false; + } +} + +class H1 { + final T t; + final U u; + + List get listOfT => [t]; + List get listOfU => [u]; + + H1(this.t, this.u); +} + +typedef H2 = H1; + +bool typedefResolvingToInterfaceType(Object o) { + switch (o) { + case H2(listOfT: var x, listOfU: var y): + x.expectStaticType>>(); + y.expectStaticType>>(); + o.expectStaticType>>(); + return true; + default: + return false; + } +} + +typedef I = String Function(S); + +bool typedefResolvingToFunctionType(Object o) { + switch (o) { + case I(): + o.expectStaticType>>(); + return true; + default: + return false; } } main() { - explicitTypeArguments(C(0)); - simpleInference(C(0)); - inferDynamic(C(0)); - inferBound(D(0)); - E(0, '') - .inferEnclosingTypeParameters(E, Set>({''}, {0})); - fBounded(F2()); - partialInference(G2(0, {0})); + Expect.isTrue(explicitTypeArguments(C(0))); + Expect.isTrue(simpleInference(C(0))); + Expect.isTrue(inferDynamic(C(0))); + Expect.isFalse(inferDynamic(0)); + Expect.isTrue(inferBound(D(0))); + Expect.isFalse(inferBound(0)); + Expect.isTrue(E(0, '') + .inferEnclosingTypeParameters(E, Set>({''}, {0}))); + Expect.isTrue(fBounded(F2())); + Expect.isFalse(fBounded(0)); + Expect.isTrue(partialInference(G2(0, {0}))); + Expect.isFalse(partialInference(G1(0))); + Expect.isTrue(typedefResolvingToInterfaceType(H1(0, ''))); + Expect.isTrue(typedefResolvingToInterfaceType(H1(0, ''))); + Expect.isFalse(typedefResolvingToInterfaceType(H1(0, ''))); + Expect.isTrue(typedefResolvingToFunctionType((Object o) => o.toString())); + Expect.isTrue(typedefResolvingToFunctionType((num n) => n.toString())); + Expect.isFalse(typedefResolvingToFunctionType((int i) => i.toString())); }