diff --git a/pkg/front_end/testcases/general/issue56633.dart b/pkg/front_end/testcases/general/issue56633.dart new file mode 100644 index 000000000000..f610aa304a5e --- /dev/null +++ b/pkg/front_end/testcases/general/issue56633.dart @@ -0,0 +1,12 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +T Function() method(S Function() f) => f; + +abstract class A { + T Function(S s) foo = (S s) => s; +} + +typedef F = int; +typedef G = F Function(); diff --git a/pkg/front_end/testcases/general/issue56633.dart.strong.expect b/pkg/front_end/testcases/general/issue56633.dart.strong.expect new file mode 100644 index 000000000000..37aa6d843dc1 --- /dev/null +++ b/pkg/front_end/testcases/general/issue56633.dart.strong.expect @@ -0,0 +1,20 @@ +library; +import self as self; +import "dart:core" as core; + +typedef F = core::int; +typedef G = () → core::int; +abstract class A extends core::Object { + covariant-by-class field (S%) → self::A::T% foo = (S% s) → S% => s; + synthetic constructor •() → self::A + : super core::Object::•() + ; +} +static method method(() → S% f) → () → self::method::T% + return f; +static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm_shared/lib/integers_patch.dart */ _#F#fromEnvironment#tearOff(core::String name, {core::int defaultValue = #C1}) → core::int + return core::int::fromEnvironment(name, defaultValue: defaultValue); + +constants { + #C1 = 0 +} diff --git a/pkg/front_end/testcases/general/issue56633.dart.strong.modular.expect b/pkg/front_end/testcases/general/issue56633.dart.strong.modular.expect new file mode 100644 index 000000000000..37aa6d843dc1 --- /dev/null +++ b/pkg/front_end/testcases/general/issue56633.dart.strong.modular.expect @@ -0,0 +1,20 @@ +library; +import self as self; +import "dart:core" as core; + +typedef F = core::int; +typedef G = () → core::int; +abstract class A extends core::Object { + covariant-by-class field (S%) → self::A::T% foo = (S% s) → S% => s; + synthetic constructor •() → self::A + : super core::Object::•() + ; +} +static method method(() → S% f) → () → self::method::T% + return f; +static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm_shared/lib/integers_patch.dart */ _#F#fromEnvironment#tearOff(core::String name, {core::int defaultValue = #C1}) → core::int + return core::int::fromEnvironment(name, defaultValue: defaultValue); + +constants { + #C1 = 0 +} diff --git a/pkg/front_end/testcases/general/issue56633.dart.strong.outline.expect b/pkg/front_end/testcases/general/issue56633.dart.strong.outline.expect new file mode 100644 index 000000000000..3534b2a47e2e --- /dev/null +++ b/pkg/front_end/testcases/general/issue56633.dart.strong.outline.expect @@ -0,0 +1,15 @@ +library; +import self as self; +import "dart:core" as core; + +typedef F = core::int; +typedef G = () → core::int; +abstract class A extends core::Object { + covariant-by-class field (S%) → self::A::T% foo; + synthetic constructor •() → self::A + ; +} +static method method(() → S% f) → () → self::method::T% + ; +static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm_shared/lib/integers_patch.dart */ _#F#fromEnvironment#tearOff(core::String name, {has-declared-initializer core::int defaultValue}) → core::int + return core::int::fromEnvironment(name, defaultValue: defaultValue); diff --git a/pkg/front_end/testcases/general/issue56633.dart.strong.transformed.expect b/pkg/front_end/testcases/general/issue56633.dart.strong.transformed.expect new file mode 100644 index 000000000000..37aa6d843dc1 --- /dev/null +++ b/pkg/front_end/testcases/general/issue56633.dart.strong.transformed.expect @@ -0,0 +1,20 @@ +library; +import self as self; +import "dart:core" as core; + +typedef F = core::int; +typedef G = () → core::int; +abstract class A extends core::Object { + covariant-by-class field (S%) → self::A::T% foo = (S% s) → S% => s; + synthetic constructor •() → self::A + : super core::Object::•() + ; +} +static method method(() → S% f) → () → self::method::T% + return f; +static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm_shared/lib/integers_patch.dart */ _#F#fromEnvironment#tearOff(core::String name, {core::int defaultValue = #C1}) → core::int + return core::int::fromEnvironment(name, defaultValue: defaultValue); + +constants { + #C1 = 0 +} diff --git a/pkg/front_end/testcases/general/issue56633.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue56633.dart.textual_outline.expect new file mode 100644 index 000000000000..3e2890873e1f --- /dev/null +++ b/pkg/front_end/testcases/general/issue56633.dart.textual_outline.expect @@ -0,0 +1,9 @@ +T Function() method(S Function() f) => f; + +abstract class A { + T Function(S s) foo = (S s) => s; +} + +typedef F = int; + +typedef G = F Function(); diff --git a/pkg/front_end/testcases/general/issue56633.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue56633.dart.textual_outline_modelled.expect new file mode 100644 index 000000000000..3e2890873e1f --- /dev/null +++ b/pkg/front_end/testcases/general/issue56633.dart.textual_outline_modelled.expect @@ -0,0 +1,9 @@ +T Function() method(S Function() f) => f; + +abstract class A { + T Function(S s) foo = (S s) => s; +} + +typedef F = int; + +typedef G = F Function(); diff --git a/pkg/kernel/lib/src/types.dart b/pkg/kernel/lib/src/types.dart index 72947276b13d..f3d28a6b22c4 100644 --- a/pkg/kernel/lib/src/types.dart +++ b/pkg/kernel/lib/src/types.dart @@ -407,8 +407,20 @@ class Types with StandardBounds { return result.and(new IsSubtypeOf.basedSolelyOnNullabilities( sTypeParameterType, tTypeParameterType)); - case (StructuralParameterType(), TypeParameterType()): - return const IsSubtypeOf.never(); + case ( + StructuralParameterType sStructuralParameterType, + TypeParameterType tTypeParameterType + ): + IsSubtypeOf result = performNullabilityAwareSubtypeCheck( + sStructuralParameterType.bound, t); + if (sStructuralParameterType.nullability == Nullability.undetermined && + tTypeParameterType.nullability == Nullability.undetermined) { + // The two nullabilities are undetermined, but are connected via + // additional constraint, namely that they will be equal at run time. + return result; + } + return result.and(new IsSubtypeOf.basedSolelyOnNullabilities( + sStructuralParameterType, tTypeParameterType)); case ( IntersectionType sIntersectionType,