Skip to content

Commit

Permalink
[cfe] Handle structural against type parameter type in subtype tests
Browse files Browse the repository at this point in the history
Closes #56633

This is also a follow-up to
https://dart-review.googlesource.com/c/sdk/+/382000/comment/9801301a_05a82175/

Change-Id: Id6f791292ee424ca0bf971cdd0c99dfbb6b79a10
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/385421
Reviewed-by: Johnni Winther <[email protected]>
Commit-Queue: Chloe Stefantsova <[email protected]>
  • Loading branch information
chloestefantsova authored and Commit Queue committed Sep 17, 2024
1 parent dfb414a commit cfcea0b
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 2 deletions.
12 changes: 12 additions & 0 deletions pkg/front_end/testcases/general/issue56633.dart
Original file line number Diff line number Diff line change
@@ -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<S extends T>() method<T>(S Function<S extends T>() f) => f;

abstract class A<T> {
T Function<S extends T>(S s) foo = <S extends T>(S s) => s;
}

typedef F<T, S extends T> = int;
typedef G<T> = F<T, S> Function<S extends T>();
20 changes: 20 additions & 0 deletions pkg/front_end/testcases/general/issue56633.dart.strong.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
library;
import self as self;
import "dart:core" as core;

typedef F<unrelated T extends core::Object? = dynamic, unrelated S extends T% = dynamic> = core::int;
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>() → core::int;
abstract class A<T extends core::Object? = dynamic> extends core::Object {
covariant-by-class field <S extends self::A::T% = dynamic>(S%) → self::A::T% foo = <S extends self::A::T%>(S% s) → S% => s;
synthetic constructor •() → self::A<self::A::T%>
: super core::Object::•()
;
}
static method method<T extends core::Object? = dynamic>(<S extends self::method::T% = dynamic>() → S% f) → <S extends self::method::T% = dynamic>() → self::method::T%
return f;
static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm_shared/lib/integers_patch.dart */ _#F#fromEnvironment#tearOff<unrelated T extends core::Object? = dynamic, unrelated S extends self::_#F#fromEnvironment#tearOff::T% = dynamic>(core::String name, {core::int defaultValue = #C1}) → core::int
return core::int::fromEnvironment(name, defaultValue: defaultValue);

constants {
#C1 = 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
library;
import self as self;
import "dart:core" as core;

typedef F<unrelated T extends core::Object? = dynamic, unrelated S extends T% = dynamic> = core::int;
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>() → core::int;
abstract class A<T extends core::Object? = dynamic> extends core::Object {
covariant-by-class field <S extends self::A::T% = dynamic>(S%) → self::A::T% foo = <S extends self::A::T%>(S% s) → S% => s;
synthetic constructor •() → self::A<self::A::T%>
: super core::Object::•()
;
}
static method method<T extends core::Object? = dynamic>(<S extends self::method::T% = dynamic>() → S% f) → <S extends self::method::T% = dynamic>() → self::method::T%
return f;
static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm_shared/lib/integers_patch.dart */ _#F#fromEnvironment#tearOff<unrelated T extends core::Object? = dynamic, unrelated S extends self::_#F#fromEnvironment#tearOff::T% = dynamic>(core::String name, {core::int defaultValue = #C1}) → core::int
return core::int::fromEnvironment(name, defaultValue: defaultValue);

constants {
#C1 = 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
library;
import self as self;
import "dart:core" as core;

typedef F<unrelated T extends core::Object? = dynamic, unrelated S extends T% = dynamic> = core::int;
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>() → core::int;
abstract class A<T extends core::Object? = dynamic> extends core::Object {
covariant-by-class field <S extends self::A::T% = dynamic>(S%) → self::A::T% foo;
synthetic constructor •() → self::A<self::A::T%>
;
}
static method method<T extends core::Object? = dynamic>(<S extends self::method::T% = dynamic>() → S% f) → <S extends self::method::T% = dynamic>() → self::method::T%
;
static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm_shared/lib/integers_patch.dart */ _#F#fromEnvironment#tearOff<unrelated T extends core::Object? = dynamic, unrelated S extends self::_#F#fromEnvironment#tearOff::T% = dynamic>(core::String name, {has-declared-initializer core::int defaultValue}) → core::int
return core::int::fromEnvironment(name, defaultValue: defaultValue);
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
library;
import self as self;
import "dart:core" as core;

typedef F<unrelated T extends core::Object? = dynamic, unrelated S extends T% = dynamic> = core::int;
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>() → core::int;
abstract class A<T extends core::Object? = dynamic> extends core::Object {
covariant-by-class field <S extends self::A::T% = dynamic>(S%) → self::A::T% foo = <S extends self::A::T%>(S% s) → S% => s;
synthetic constructor •() → self::A<self::A::T%>
: super core::Object::•()
;
}
static method method<T extends core::Object? = dynamic>(<S extends self::method::T% = dynamic>() → S% f) → <S extends self::method::T% = dynamic>() → self::method::T%
return f;
static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm_shared/lib/integers_patch.dart */ _#F#fromEnvironment#tearOff<unrelated T extends core::Object? = dynamic, unrelated S extends self::_#F#fromEnvironment#tearOff::T% = dynamic>(core::String name, {core::int defaultValue = #C1}) → core::int
return core::int::fromEnvironment(name, defaultValue: defaultValue);

constants {
#C1 = 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
T Function<S extends T>() method<T>(S Function<S extends T>() f) => f;

abstract class A<T> {
T Function<S extends T>(S s) foo = <S extends T>(S s) => s;
}

typedef F<T, S extends T> = int;

typedef G<T> = F<T, S> Function<S extends T>();
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
T Function<S extends T>() method<T>(S Function<S extends T>() f) => f;

abstract class A<T> {
T Function<S extends T>(S s) foo = <S extends T>(S s) => s;
}

typedef F<T, S extends T> = int;

typedef G<T> = F<T, S> Function<S extends T>();
16 changes: 14 additions & 2 deletions pkg/kernel/lib/src/types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit cfcea0b

Please sign in to comment.