mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:21:07 +00:00
Correct implementation of expand-to-type-variable error check
Bug: #45351 Change-Id: I0f7a813c8da8ce2f60cdcd3d81d854e75556130f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/192743 Commit-Queue: Erik Ernst <eernst@google.com> Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
This commit is contained in:
parent
1453eebebc
commit
6db2f7a2f6
|
@ -682,7 +682,10 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl
|
|||
TypeAliasBuilder aliasBuilder; // Non-null if a type alias is use.
|
||||
if (decl is TypeAliasBuilder) {
|
||||
aliasBuilder = decl;
|
||||
decl = aliasBuilder.unaliasDeclaration(superClassType.arguments);
|
||||
decl = aliasBuilder.unaliasDeclaration(superClassType.arguments,
|
||||
isUsedAsClass: true,
|
||||
usedAsClassCharOffset: supertypeBuilder.charOffset,
|
||||
usedAsClassFileUri: superClassType.fileUri);
|
||||
}
|
||||
// TODO(eernst): Should gather 'restricted supertype' checks in one place,
|
||||
// e.g., dynamic/int/String/Null and more are checked elsewhere.
|
||||
|
@ -708,7 +711,10 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl
|
|||
TypeAliasBuilder aliasBuilder; // Non-null if a type alias is used.
|
||||
if (typeDeclaration is TypeAliasBuilder) {
|
||||
aliasBuilder = typeDeclaration;
|
||||
decl = aliasBuilder.unaliasDeclaration(type.arguments);
|
||||
decl = aliasBuilder.unaliasDeclaration(type.arguments,
|
||||
isUsedAsClass: true,
|
||||
usedAsClassCharOffset: type.charOffset,
|
||||
usedAsClassFileUri: type.fileUri);
|
||||
} else {
|
||||
decl = typeDeclaration;
|
||||
}
|
||||
|
@ -1149,7 +1155,10 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl
|
|||
if (builder is ClassBuilder) return builder;
|
||||
if (builder is TypeAliasBuilder) {
|
||||
TypeDeclarationBuilder declarationBuilder =
|
||||
builder.unaliasDeclaration(supertype.arguments);
|
||||
builder.unaliasDeclaration(supertype.arguments,
|
||||
isUsedAsClass: true,
|
||||
usedAsClassCharOffset: supertype.charOffset,
|
||||
usedAsClassFileUri: supertype.fileUri);
|
||||
if (declarationBuilder is ClassBuilder) return declarationBuilder;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,14 +81,14 @@ abstract class TypeAliasBuilder implements TypeDeclarationBuilder {
|
|||
/// based on the given [typeArguments]. It expands type aliases repeatedly
|
||||
/// until it encounters a builder which is not a [TypeAliasBuilder].
|
||||
///
|
||||
/// If [isInvocation] is false: In this case it is required that
|
||||
/// If [isUsedAsClass] is false: In this case it is required that
|
||||
/// `typeArguments.length == typeVariables.length`. The [typeArguments] are
|
||||
/// threaded through the expansion if needed, and the resulting declaration
|
||||
/// is returned.
|
||||
///
|
||||
/// If [isInvocation] is true: In this case [typeArguments] are ignored, but
|
||||
/// [invocationCharOffset] and [invocationFileUri] must be non-null. If `this`
|
||||
/// type alias expands in one or more steps to a builder which is not a
|
||||
/// If [isUsedAsClass] is true: In this case [typeArguments] are ignored, but
|
||||
/// [usedAsClassCharOffset] and [usedAsClassFileUri] must be non-null. If
|
||||
/// `this` type alias expands in one or more steps to a builder which is not a
|
||||
/// [TypeAliasBuilder] nor a [TypeVariableBuilder] then that builder is
|
||||
/// returned. If this type alias is cyclic or expands to an invalid type or
|
||||
/// a type that does not have a declaration (say, a function type) then `this`
|
||||
|
@ -97,9 +97,9 @@ abstract class TypeAliasBuilder implements TypeDeclarationBuilder {
|
|||
/// [TypeVariableBuilder] then the type alias cannot be used in a constructor
|
||||
/// invocation. Then an error is emitted and `this` is returned.
|
||||
TypeDeclarationBuilder unaliasDeclaration(List<TypeBuilder> typeArguments,
|
||||
{bool isInvocation = false,
|
||||
int invocationCharOffset,
|
||||
Uri invocationFileUri});
|
||||
{bool isUsedAsClass = false,
|
||||
int usedAsClassCharOffset,
|
||||
Uri usedAsClassFileUri});
|
||||
|
||||
/// Compute type arguments passed to [ClassBuilder] from unaliasDeclaration.
|
||||
/// This method does not check for cycles and may only be called if an
|
||||
|
@ -191,25 +191,32 @@ abstract class TypeAliasBuilderImpl extends TypeDeclarationBuilderImpl
|
|||
/// based on the given [typeArguments]. It expands type aliases repeatedly
|
||||
/// until it encounters a builder which is not a [TypeAliasBuilder].
|
||||
///
|
||||
/// If [isInvocation] is false: In this case it is required that
|
||||
/// The parameter [isUsedAsClass] indicates whether the type alias is being
|
||||
/// used as a class, e.g., as the class in an instance creation, as a
|
||||
/// superinterface, in a redirecting factory constructor, or to invoke a
|
||||
/// static member.
|
||||
///
|
||||
/// If [isUsedAsClass] is false: In this case it is required that
|
||||
/// `typeArguments.length == typeVariables.length`. The [typeArguments] are
|
||||
/// threaded through the expansion if needed, and the resulting declaration
|
||||
/// is returned.
|
||||
///
|
||||
/// If [isInvocation] is true: In this case [typeArguments] are ignored, but
|
||||
/// [invocationCharOffset] and [invocationFileUri] must be non-null. If `this`
|
||||
/// If [isUsedAsClass] is true: In this case [typeArguments] can be null, but
|
||||
/// [usedAsClassCharOffset] and [usedAsClassFileUri] must be non-null. When
|
||||
/// [typeArguments] is null, the returned [TypeDeclarationBuilder] indicates
|
||||
/// which class the type alias denotes, without type arguments. If `this`
|
||||
/// type alias expands in one or more steps to a builder which is not a
|
||||
/// [TypeAliasBuilder] nor a [TypeVariableBuilder] then that builder is
|
||||
/// returned. If this type alias is cyclic or expands to an invalid type or
|
||||
/// a type that does not have a declaration (say, a function type) then `this`
|
||||
/// is returned (when the type was invalid: with `thisType` set to
|
||||
/// `const InvalidType()`). If `this` type alias expands to a
|
||||
/// [TypeVariableBuilder] then the type alias cannot be used in a constructor
|
||||
/// invocation. Then an error is emitted and `this` is returned.
|
||||
/// [TypeVariableBuilder] then the type alias cannot be used as a class, in
|
||||
/// which case an error is emitted and `this` is returned.
|
||||
TypeDeclarationBuilder unaliasDeclaration(List<TypeBuilder> typeArguments,
|
||||
{bool isInvocation = false,
|
||||
int invocationCharOffset,
|
||||
Uri invocationFileUri}) {
|
||||
{bool isUsedAsClass = false,
|
||||
int usedAsClassCharOffset,
|
||||
Uri usedAsClassFileUri}) {
|
||||
if (_cachedUnaliasedDeclaration != null) return _cachedUnaliasedDeclaration;
|
||||
Set<TypeDeclarationBuilder> builders = {this};
|
||||
TypeDeclarationBuilder current = this;
|
||||
|
@ -241,15 +248,39 @@ abstract class TypeAliasBuilderImpl extends TypeDeclarationBuilderImpl
|
|||
// `_cachedUnaliasedDeclaration` because it changes from call to call
|
||||
// with type aliases of this kind. Note that every `aliasBuilder.type`
|
||||
// up to this point is a [NamedTypeBuilder], because only they can have
|
||||
// a non-null `type`. However, a constructor invocation is not admitted.
|
||||
if (isInvocation) {
|
||||
library.addProblem(messageTypedefTypeVariableNotConstructor,
|
||||
invocationCharOffset, noLength, invocationFileUri,
|
||||
context: [
|
||||
messageTypedefTypeVariableNotConstructorCause.withLocation(
|
||||
current.fileUri, current.charOffset, noLength),
|
||||
]);
|
||||
return this;
|
||||
// a non-null `type`. However, this type alias can not be used as a
|
||||
// class.
|
||||
if (isUsedAsClass) {
|
||||
List<TypeBuilder> freshTypeArguments = [
|
||||
if (typeVariables != null)
|
||||
for (TypeVariableBuilder typeVariable in typeVariables)
|
||||
new NamedTypeBuilder.fromTypeDeclarationBuilder(
|
||||
typeVariable,
|
||||
library.nonNullableBuilder,
|
||||
const [],
|
||||
fileUri,
|
||||
charOffset,
|
||||
),
|
||||
];
|
||||
TypeDeclarationBuilder typeDeclarationBuilder =
|
||||
_unaliasDeclaration(freshTypeArguments);
|
||||
bool found = false;
|
||||
for (TypeBuilder typeBuilder in freshTypeArguments) {
|
||||
if (typeBuilder.declaration == typeDeclarationBuilder) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
library.addProblem(messageTypedefTypeVariableNotConstructor,
|
||||
usedAsClassCharOffset, noLength, usedAsClassFileUri,
|
||||
context: [
|
||||
messageTypedefTypeVariableNotConstructorCause.withLocation(
|
||||
current.fileUri, current.charOffset, noLength),
|
||||
]);
|
||||
return this;
|
||||
}
|
||||
if (typeArguments == null) return typeDeclarationBuilder;
|
||||
}
|
||||
return _unaliasDeclaration(typeArguments);
|
||||
}
|
||||
|
|
|
@ -4530,9 +4530,9 @@ class BodyBuilder extends ScopeListener<JumpTarget>
|
|||
noLength));
|
||||
}
|
||||
type = aliasBuilder.unaliasDeclaration(null,
|
||||
isInvocation: true,
|
||||
invocationCharOffset: nameToken.charOffset,
|
||||
invocationFileUri: uri);
|
||||
isUsedAsClass: true,
|
||||
usedAsClassCharOffset: nameToken.charOffset,
|
||||
usedAsClassFileUri: uri);
|
||||
List<TypeBuilder> typeArgumentBuilders = [];
|
||||
if (typeArguments != null) {
|
||||
for (UnresolvedType unresolvedType in typeArguments) {
|
||||
|
|
|
@ -1374,7 +1374,10 @@ class ClassHierarchyNodeBuilder {
|
|||
if (mixin is TypeAliasBuilder) {
|
||||
TypeAliasBuilder aliasBuilder = mixin;
|
||||
NamedTypeBuilder namedBuilder = mixedInTypeBuilder;
|
||||
mixin = aliasBuilder.unaliasDeclaration(namedBuilder.arguments);
|
||||
mixin = aliasBuilder.unaliasDeclaration(namedBuilder.arguments,
|
||||
isUsedAsClass: true,
|
||||
usedAsClassCharOffset: namedBuilder.charOffset,
|
||||
usedAsClassFileUri: namedBuilder.fileUri);
|
||||
}
|
||||
if (mixin is ClassBuilder) {
|
||||
scope = mixin.scope.computeMixinScope();
|
||||
|
|
|
@ -3061,9 +3061,9 @@ class TypeUseGenerator extends ReadOnlyAccessGenerator {
|
|||
if (declarationBuilder is TypeAliasBuilder) {
|
||||
TypeAliasBuilder aliasBuilder = declarationBuilder;
|
||||
declarationBuilder = aliasBuilder.unaliasDeclaration(null,
|
||||
isInvocation: true,
|
||||
invocationCharOffset: this.fileOffset,
|
||||
invocationFileUri: _uri);
|
||||
isUsedAsClass: true,
|
||||
usedAsClassCharOffset: this.fileOffset,
|
||||
usedAsClassFileUri: _uri);
|
||||
}
|
||||
if (declarationBuilder is DeclarationBuilder) {
|
||||
DeclarationBuilder declaration = declarationBuilder;
|
||||
|
|
|
@ -675,7 +675,10 @@ class KernelTarget extends TargetImplementation {
|
|||
if (supertype is TypeAliasBuilder) {
|
||||
TypeAliasBuilder aliasBuilder = supertype;
|
||||
NamedTypeBuilder namedBuilder = type;
|
||||
supertype = aliasBuilder.unaliasDeclaration(namedBuilder.arguments);
|
||||
supertype = aliasBuilder.unaliasDeclaration(namedBuilder.arguments,
|
||||
isUsedAsClass: true,
|
||||
usedAsClassCharOffset: namedBuilder.charOffset,
|
||||
usedAsClassFileUri: namedBuilder.fileUri);
|
||||
}
|
||||
if (supertype is SourceClassBuilder && supertype.isMixinApplication) {
|
||||
installForwardingConstructors(supertype);
|
||||
|
|
|
@ -589,8 +589,11 @@ class SourceClassBuilder extends ClassBuilderImpl
|
|||
if (declarationBuilder is TypeAliasBuilder) {
|
||||
TypeAliasBuilder aliasBuilder = declarationBuilder;
|
||||
NamedTypeBuilder namedBuilder = supertype;
|
||||
declarationBuilder =
|
||||
aliasBuilder.unaliasDeclaration(namedBuilder.arguments);
|
||||
declarationBuilder = aliasBuilder.unaliasDeclaration(
|
||||
namedBuilder.arguments,
|
||||
isUsedAsClass: true,
|
||||
usedAsClassCharOffset: namedBuilder.charOffset,
|
||||
usedAsClassFileUri: namedBuilder.fileUri);
|
||||
result[declarationBuilder] = aliasBuilder;
|
||||
} else {
|
||||
result[declarationBuilder] = null;
|
||||
|
@ -606,8 +609,11 @@ class SourceClassBuilder extends ClassBuilderImpl
|
|||
if (declarationBuilder is TypeAliasBuilder) {
|
||||
TypeAliasBuilder aliasBuilder = declarationBuilder;
|
||||
NamedTypeBuilder namedBuilder = interface;
|
||||
declarationBuilder =
|
||||
aliasBuilder.unaliasDeclaration(namedBuilder.arguments);
|
||||
declarationBuilder = aliasBuilder.unaliasDeclaration(
|
||||
namedBuilder.arguments,
|
||||
isUsedAsClass: true,
|
||||
usedAsClassCharOffset: namedBuilder.charOffset,
|
||||
usedAsClassFileUri: namedBuilder.fileUri);
|
||||
result[declarationBuilder] = aliasBuilder;
|
||||
} else {
|
||||
result[declarationBuilder] = null;
|
||||
|
@ -621,8 +627,11 @@ class SourceClassBuilder extends ClassBuilderImpl
|
|||
if (declarationBuilder is TypeAliasBuilder) {
|
||||
TypeAliasBuilder aliasBuilder = declarationBuilder;
|
||||
NamedTypeBuilder namedBuilder = mixedInTypeBuilder;
|
||||
declarationBuilder =
|
||||
aliasBuilder.unaliasDeclaration(namedBuilder.arguments);
|
||||
declarationBuilder = aliasBuilder.unaliasDeclaration(
|
||||
namedBuilder.arguments,
|
||||
isUsedAsClass: true,
|
||||
usedAsClassCharOffset: namedBuilder.charOffset,
|
||||
usedAsClassFileUri: namedBuilder.fileUri);
|
||||
result[declarationBuilder] = aliasBuilder;
|
||||
} else {
|
||||
result[declarationBuilder] = null;
|
||||
|
|
|
@ -907,7 +907,10 @@ class SourceLoader extends Loader {
|
|||
if (builder is TypeAliasBuilder) {
|
||||
TypeAliasBuilder aliasBuilder = builder;
|
||||
NamedTypeBuilder namedBuilder = mixedInTypeBuilder;
|
||||
builder = aliasBuilder.unaliasDeclaration(namedBuilder.arguments);
|
||||
builder = aliasBuilder.unaliasDeclaration(namedBuilder.arguments,
|
||||
isUsedAsClass: true,
|
||||
usedAsClassCharOffset: namedBuilder.charOffset,
|
||||
usedAsClassFileUri: namedBuilder.fileUri);
|
||||
if (builder is! ClassBuilder) {
|
||||
cls.addProblem(
|
||||
templateIllegalMixin.withArguments(builder.fullNameForErrors),
|
||||
|
|
|
@ -21,22 +21,45 @@ abstract class C {
|
|||
// [cfe] unspecified
|
||||
}
|
||||
|
||||
class D1<X> extends T<X> {}
|
||||
// ^
|
||||
class D {}
|
||||
mixin M {}
|
||||
|
||||
abstract class D1<X> extends T<D> {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D2 extends C with T<int> {}
|
||||
abstract class D2 extends C with T<M> {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D3<X, Y> implements T<T> {}
|
||||
abstract class D3<X, Y> implements T<T<D>> {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D4 = C with T<void>;
|
||||
abstract class D4 = C with T<D>;
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
class D5<X> extends T<X> {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D6 extends C with T<int> {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D7<X, Y> implements T<T> {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D8 = C with T<void>;
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
|
|
@ -45,12 +45,6 @@ class C1 implements C {
|
|||
}
|
||||
|
||||
class D {}
|
||||
mixin M {}
|
||||
|
||||
abstract class D1<X> extends T<D> {}
|
||||
abstract class D2 extends C with T<M> {}
|
||||
abstract class D3<X, Y> implements T<T<D>> {}
|
||||
abstract class D4 = C with T<D>;
|
||||
|
||||
extension E on T<dynamic> {
|
||||
T<dynamic> foo(T<dynamic> t) => t;
|
||||
|
|
|
@ -23,22 +23,45 @@ abstract class C {
|
|||
// [cfe] unspecified
|
||||
}
|
||||
|
||||
class D1<X> extends T<X> {}
|
||||
// ^
|
||||
class D {}
|
||||
mixin M {}
|
||||
|
||||
abstract class D1<X> extends T<D> {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D2 extends C with T<int> {}
|
||||
abstract class D2 extends C with T<M> {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D3<X, Y> implements T<T> {}
|
||||
abstract class D3<X, Y> implements T<T<D>> {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D4 = C with T<void>;
|
||||
abstract class D4 = C with T<D>;
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
class D5<X> extends T<X> {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D6 extends C with T<int> {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D7<X, Y> implements T<T> {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D8 = C with T<void>;
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
|
|
@ -47,16 +47,6 @@ class C1 implements C {
|
|||
|
||||
class D {}
|
||||
|
||||
mixin M {}
|
||||
|
||||
abstract class D1<X> extends T<D> {}
|
||||
|
||||
abstract class D2 extends C with T<M> {}
|
||||
|
||||
abstract class D3<X, Y> implements T<T<D>> {}
|
||||
|
||||
abstract class D4 = C with T<D>;
|
||||
|
||||
extension E on T<dynamic> {
|
||||
T<dynamic> foo(T<dynamic> t) => t;
|
||||
}
|
||||
|
|
|
@ -22,16 +22,28 @@ class C {
|
|||
// [cfe] unspecified
|
||||
}
|
||||
|
||||
class D1 extends T {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D2 extends C with T {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D3 implements T {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D4 = C with T;
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
X foo<X>(X x) => x;
|
||||
|
||||
main() {
|
||||
var v14 = <Set<T>, Set<T>>{{}: {}};
|
||||
v14[{}] = {T()};
|
||||
|
|
|
@ -45,10 +45,6 @@ class C1 implements C {
|
|||
noSuchMethod(Invocation invocation) => throw 0;
|
||||
}
|
||||
|
||||
class D1 extends T {}
|
||||
|
||||
abstract class D3 implements T {}
|
||||
|
||||
extension E on T {
|
||||
T foo(T t) => t;
|
||||
}
|
||||
|
@ -60,7 +56,6 @@ T Function(T) id = (x) => x;
|
|||
main() {
|
||||
var v13 = <T>[];
|
||||
var v14 = <Set<T>, Set<T>>{{}: {}};
|
||||
v14[{}] = {D1()};
|
||||
var v15 = {v13};
|
||||
Set<List<T>> v16 = v15;
|
||||
v15 = v16;
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
// 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.
|
||||
|
||||
// SharedOptions=--enable-experiment=nonfunction-type-aliases
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
typedef TB<T extends C> = T;
|
||||
typedef AC = C; // Direct.
|
||||
typedef AEC = TB<C>; // Explicit C argument.
|
||||
typedef AIC = TB; // Implicit instantiate to bounds.
|
||||
|
||||
class C {
|
||||
static const c = 42;
|
||||
static int s = 42;
|
||||
final int y;
|
||||
const C(this.y);
|
||||
const C.name(this.y);
|
||||
}
|
||||
|
||||
main() {
|
||||
const c0 = AC.c;
|
||||
const c1 = AEC.c;
|
||||
const c2 = AIC.c;
|
||||
Expect.equals(42, AC.s);
|
||||
Expect.equals(42, AEC.s);
|
||||
Expect.equals(42, AIC.s);
|
||||
Expect.equals(0, AC(0).y);
|
||||
Expect.equals(0, AEC(0).y);
|
||||
Expect.equals(0, AIC(0).y);
|
||||
Expect.equals(0, AC.name(0).y);
|
||||
Expect.equals(0, AEC.name(0).y);
|
||||
Expect.equals(0, AIC.name(0).y);
|
||||
}
|
|
@ -25,16 +25,29 @@ class C {
|
|||
// [cfe] unspecified
|
||||
}
|
||||
|
||||
class D1 extends T {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D2 extends C with T {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
abstract class D3 implements T {}
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
|
||||
abstract class D4 = C with T;
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
|
||||
X foo<X>(X x) => x;
|
||||
|
||||
main() {
|
||||
var v14 = <Set<T>, Set<T>>{{}: {}};
|
||||
v14[{}] = {T()};
|
||||
|
|
|
@ -48,9 +48,6 @@ class C1 implements C {
|
|||
noSuchMethod(Invocation invocation) => throw 0;
|
||||
}
|
||||
|
||||
class D1 extends T {}
|
||||
abstract class D3 implements T {}
|
||||
|
||||
extension E on T {
|
||||
T foo(T t) => t;
|
||||
}
|
||||
|
@ -62,7 +59,6 @@ T Function(T) id = (x) => x;
|
|||
main() {
|
||||
var v13 = <T>[];
|
||||
var v14 = <Set<T>, Set<T>>{{}: {}};
|
||||
v14[{}] = {D1()};
|
||||
var v15 = {v13};
|
||||
Set<List<T>> v16 = v15;
|
||||
v15 = v16;
|
||||
|
|
Loading…
Reference in a new issue