Skip to content

Commit

Permalink
[cfe] Allow generic types in arguments and bounds under a flag
Browse files Browse the repository at this point in the history
The flag that enables the feature is the 'generic-metadata' experiment
flag.

Bug: #44916
Change-Id: I2770c672280831bf5af6643fde9cb0f1be3083b8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/188701
Reviewed-by: Johnni Winther <[email protected]>
Commit-Queue: Dmitry Stefantsov <[email protected]>
  • Loading branch information
Dmitry Stefantsov authored and [email protected] committed Mar 4, 2021
1 parent bec37f1 commit c83d879
Show file tree
Hide file tree
Showing 27 changed files with 566 additions and 59 deletions.
8 changes: 5 additions & 3 deletions pkg/front_end/lib/src/fasta/source/source_class_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -425,19 +425,21 @@ class SourceClassBuilder extends ClassBuilderImpl
Library library = libraryBuilder.library;

List<TypeArgumentIssue> issues = findTypeArgumentIssues(
library,
new InterfaceType(
supertype.classNode, library.nonNullable, supertype.typeArguments),
typeEnvironment,
libraryBuilder.isNonNullableByDefault
? SubtypeCheckMode.withNullabilities
: SubtypeCheckMode.ignoringNullabilities,
allowSuperBounded: false);
allowSuperBounded: false,
isNonNullableByDefault: library.isNonNullableByDefault,
areGenericArgumentsAllowed:
libraryBuilder.enableGenericMetadataInLibrary);
for (TypeArgumentIssue issue in issues) {
DartType argument = issue.argument;
TypeParameter typeParameter = issue.typeParameter;
bool inferred = libraryBuilder.inferredTypes.contains(argument);
if (isGenericFunctionTypeOrAlias(argument)) {
if (issue.isGenericTypeAsArgumentIssue) {
if (inferred) {
// Supertype can't be or contain super-bounded types, so null is
// passed for super-bounded hint here.
Expand Down
62 changes: 36 additions & 26 deletions pkg/front_end/lib/src/fasta/source/source_library_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ import 'package:kernel/src/bounds_checks.dart'
TypeArgumentIssue,
findTypeArgumentIssues,
findTypeArgumentIssuesForInvocation,
getGenericTypeName,
isGenericFunctionTypeOrAlias;
getGenericTypeName;

import 'package:kernel/type_algebra.dart' show Substitution, substitute;

Expand Down Expand Up @@ -2923,15 +2922,17 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {

bool haveErroneousBounds = false;
if (!inErrorRecovery) {
for (int i = 0; i < variables.length; ++i) {
TypeVariableBuilder variable = variables[i];
List<TypeBuilder> genericFunctionTypes = <TypeBuilder>[];
findGenericFunctionTypes(variable.bound,
result: genericFunctionTypes);
if (genericFunctionTypes.length > 0) {
haveErroneousBounds = true;
addProblem(messageGenericFunctionTypeInBound, variable.charOffset,
variable.name.length, variable.fileUri);
if (!enableGenericMetadataInLibrary) {
for (int i = 0; i < variables.length; ++i) {
TypeVariableBuilder variable = variables[i];
List<TypeBuilder> genericFunctionTypes = <TypeBuilder>[];
findGenericFunctionTypes(variable.bound,
result: genericFunctionTypes);
if (genericFunctionTypes.length > 0) {
haveErroneousBounds = true;
addProblem(messageGenericFunctionTypeInBound, variable.charOffset,
variable.name.length, variable.fileUri);
}
}
}

Expand Down Expand Up @@ -3170,7 +3171,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
inferredTypes.contains(argument);
offset =
typeArgumentsInfo?.getOffsetForIndex(issue.index, offset) ?? offset;
if (isGenericFunctionTypeOrAlias(argument)) {
if (issue.isGenericTypeAsArgumentIssue) {
if (issueInferred) {
message = templateGenericFunctionTypeInferredAsActualTypeArgument
.withArguments(argument, isNonNullableByDefault);
Expand Down Expand Up @@ -3221,10 +3222,14 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
}
}

// Don't show the hint about an attempted super-bounded type if the issue
// with the argument is that it's generic.
reportTypeArgumentIssue(message, fileUri, offset,
typeParameter: typeParameter,
superBoundedAttempt: issue.enclosingType,
superBoundedAttemptInverted: issue.invertedType);
superBoundedAttempt:
issue.isGenericTypeAsArgumentIssue ? null : issue.enclosingType,
superBoundedAttemptInverted:
issue.isGenericTypeAsArgumentIssue ? null : issue.invertedType);
}
}

Expand Down Expand Up @@ -3306,13 +3311,14 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
// Check in bounds of own type variables.
for (TypeParameter parameter in typeParameters) {
List<TypeArgumentIssue> issues = findTypeArgumentIssues(
library,
parameter.bound,
typeEnvironment,
isNonNullableByDefault
? SubtypeCheckMode.withNullabilities
: SubtypeCheckMode.ignoringNullabilities,
allowSuperBounded: true);
allowSuperBounded: true,
isNonNullableByDefault: library.isNonNullableByDefault,
areGenericArgumentsAllowed: enableGenericMetadataInLibrary);
for (TypeArgumentIssue issue in issues) {
DartType argument = issue.argument;
TypeParameter typeParameter = issue.typeParameter;
Expand All @@ -3325,7 +3331,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
continue;
}

if (isGenericFunctionTypeOrAlias(argument)) {
if (issue.isGenericTypeAsArgumentIssue) {
reportTypeArgumentIssue(
messageGenericFunctionTypeUsedAsActualTypeArgument,
fileUri,
Expand Down Expand Up @@ -3382,21 +3388,22 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
}
if (!skipReturnType && returnType != null) {
List<TypeArgumentIssue> issues = findTypeArgumentIssues(
library,
returnType,
typeEnvironment,
isNonNullableByDefault
? SubtypeCheckMode.withNullabilities
: SubtypeCheckMode.ignoringNullabilities,
allowSuperBounded: true);
allowSuperBounded: true,
isNonNullableByDefault: library.isNonNullableByDefault,
areGenericArgumentsAllowed: enableGenericMetadataInLibrary);
for (TypeArgumentIssue issue in issues) {
DartType argument = issue.argument;
TypeParameter typeParameter = issue.typeParameter;

// We don't need to check if [argument] was inferred or specified
// here, because inference in return types boils down to instantiate-
// -to-bound, and it can't provide a type that violates the bound.
if (isGenericFunctionTypeOrAlias(argument)) {
if (issue.isGenericTypeAsArgumentIssue) {
reportTypeArgumentIssue(
messageGenericFunctionTypeUsedAsActualTypeArgument,
fileUri,
Expand Down Expand Up @@ -3490,13 +3497,14 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
DartType type, TypeEnvironment typeEnvironment, Uri fileUri, int offset,
{bool inferred, bool allowSuperBounded = true}) {
List<TypeArgumentIssue> issues = findTypeArgumentIssues(
library,
type,
typeEnvironment,
isNonNullableByDefault
? SubtypeCheckMode.withNullabilities
: SubtypeCheckMode.ignoringNullabilities,
allowSuperBounded: allowSuperBounded);
allowSuperBounded: allowSuperBounded,
isNonNullableByDefault: library.isNonNullableByDefault,
areGenericArgumentsAllowed: enableGenericMetadataInLibrary);
reportTypeArgumentIssues(issues, fileUri, offset, inferred: inferred);
}

Expand Down Expand Up @@ -3554,14 +3562,15 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
? const NeverType.nonNullable()
: const NullType();
List<TypeArgumentIssue> issues = findTypeArgumentIssuesForInvocation(
library,
parameters,
arguments,
typeEnvironment,
isNonNullableByDefault
? SubtypeCheckMode.withNullabilities
: SubtypeCheckMode.ignoringNullabilities,
bottomType);
bottomType,
isNonNullableByDefault: library.isNonNullableByDefault,
areGenericArgumentsAllowed: enableGenericMetadataInLibrary);
if (issues.isNotEmpty) {
DartType targetReceiver;
if (klass != null) {
Expand Down Expand Up @@ -3631,14 +3640,15 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
? const NeverType.nonNullable()
: const NullType();
List<TypeArgumentIssue> issues = findTypeArgumentIssuesForInvocation(
library,
instantiatedMethodParameters,
arguments.types,
typeEnvironment,
isNonNullableByDefault
? SubtypeCheckMode.withNullabilities
: SubtypeCheckMode.ignoringNullabilities,
bottomType);
bottomType,
isNonNullableByDefault: library.isNonNullableByDefault,
areGenericArgumentsAllowed: enableGenericMetadataInLibrary);
reportTypeArgumentIssues(issues, fileUri, offset,
typeArgumentsInfo: getTypeArgumentsInfo(arguments),
targetReceiver: receiverType,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) 2021, 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.

class A<X> {}

A<Y> foo<Y>(Y y) => throw 42;

test() {
var x = foo(<Z>(Z) => throw 42);
var y = [foo];
var z = {y.first};
}

main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:collection" as col;

class A<X extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::A<self::A::X%>
: super core::Object::•()
;
}
static method foo<Y extends core::Object? = dynamic>(self::foo::Y% y) → self::A<self::foo::Y%>
return throw 42;
static method test() → dynamic {
self::A<<Z extends core::Object? = dynamic>(dynamic) → Never> x = self::foo<<Z extends core::Object? = dynamic>(dynamic) → Never>(<Z extends core::Object? = dynamic>(dynamic Z) → Never => throw 42);
core::List<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> y = <<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>[#C1];
core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> z = block {
final core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> #t1 = col::LinkedHashSet::•<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>();
#t1.{core::Set::add}{Invariant}(y.{core::Iterable::first});
} =>#t1;
}
static method main() → dynamic {}

constants {
#C1 = tearoff self::foo
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:collection" as col;

class A<X extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::A<self::A::X%>
: super core::Object::•()
;
}
static method foo<Y extends core::Object? = dynamic>(self::foo::Y% y) → self::A<self::foo::Y%>
return throw 42;
static method test() → dynamic {
self::A<<Z extends core::Object? = dynamic>(dynamic) → Never> x = self::foo<<Z extends core::Object? = dynamic>(dynamic) → Never>(<Z extends core::Object? = dynamic>(dynamic Z) → Never => throw 42);
core::List<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> y = core::_GrowableList::_literal1<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>(#C1);
core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> z = block {
final core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> #t1 = new col::_CompactLinkedHashSet::•<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>();
#t1.{core::Set::add}{Invariant}(y.{core::Iterable::first});
} =>#t1;
}
static method main() → dynamic {}

constants {
#C1 = tearoff self::foo
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class A<X> {}

A<Y> foo<Y>(Y y) => throw 42;
test() {}
main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
A<Y> foo<Y>(Y y) => throw 42;

class A<X> {}

main() {}
test() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:collection" as col;

class A<X extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::A<self::A::X%>
: super core::Object::•()
;
}
static method foo<Y extends core::Object? = dynamic>(self::foo::Y% y) → self::A<self::foo::Y%>
return throw 42;
static method test() → dynamic {
self::A<<Z extends core::Object? = dynamic>(dynamic) → Never> x = self::foo<<Z extends core::Object? = dynamic>(dynamic) → Never>(<Z extends core::Object? = dynamic>(dynamic Z) → Never => throw 42);
core::List<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> y = <<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>[#C1];
core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> z = block {
final core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> #t1 = col::LinkedHashSet::•<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>();
#t1.{core::Set::add}{Invariant}(y.{core::Iterable::first});
} =>#t1;
}
static method main() → dynamic {}

constants {
#C1 = tearoff self::foo
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;

class A<X extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::A<self::A::X%>
;
}
static method foo<Y extends core::Object? = dynamic>(self::foo::Y% y) → self::A<self::foo::Y%>
;
static method test() → dynamic
;
static method main() → dynamic
;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:collection" as col;

class A<X extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::A<self::A::X%>
: super core::Object::•()
;
}
static method foo<Y extends core::Object? = dynamic>(self::foo::Y% y) → self::A<self::foo::Y%>
return throw 42;
static method test() → dynamic {
self::A<<Z extends core::Object? = dynamic>(dynamic) → Never> x = self::foo<<Z extends core::Object? = dynamic>(dynamic) → Never>(<Z extends core::Object? = dynamic>(dynamic Z) → Never => throw 42);
core::List<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> y = core::_GrowableList::_literal1<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>(#C1);
core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> z = block {
final core::Set<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>> #t1 = new col::_CompactLinkedHashSet::•<<Y extends core::Object? = dynamic>(Y%) → self::A<Y%>>();
#t1.{core::Set::add}{Invariant}(y.{core::Iterable::first});
} =>#t1;
}
static method main() → dynamic {}

constants {
#C1 = tearoff self::foo
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) 2021, 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.

class A<X> {}

A<Function<Y>(Y)> foo(A<Function<Y>(Y)> x) => throw 42;

class B extends A<Function<Y>(Y)> {}

class C<Z extends Function<Y>(Y)> {}

bar<V extends Function<Y>(Y)>() => throw 42;

main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;

class A<X extends core::Object? = dynamic> extends core::Object {
synthetic constructor •() → self::A<self::A::X%>
: super core::Object::•()
;
}
class B extends self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> {
synthetic constructor •() → self::B
: super self::A::•()
;
}
class C<Z extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic> extends core::Object {
synthetic constructor •() → self::C<self::C::Z>
: super core::Object::•()
;
}
static method foo(self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic> x) → self::A<<Y extends core::Object? = dynamic>(Y%) → dynamic>
return throw 42;
static method bar<V extends <Y extends core::Object? = dynamic>(Y%) → dynamic = <Y extends core::Object? = dynamic>(Y%) → dynamic>() → dynamic
return throw 42;
static method main() → dynamic {}
Loading

0 comments on commit c83d879

Please sign in to comment.